{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Appendix\n", "\n", "### A-1: 対話型インタフェースの「ipywidgets」" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "bbd4806e210b47a6bf2703d2bd509c73", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=5, description='n', max=15, min=-5), Output()), _dom_classes=('widget-in…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.1:デコレータを使用したスライダ\n", "from ipywidgets import interact\n", "\n", "\n", "@interact(n=5)\n", "def f(n):\n", " return n" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "4c44c7c05b1e421e89930137a056104f", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=1, description='i', max=3, min=-1), FloatSlider(value=0.1, description='…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.2:さまざまな型を指定したinteract関数\n", "@interact(i=1, f=0.1, s=\"text\", l=[\"a\", \"b\"], is_checked=True)\n", "def f(i, f, s, l, is_checked):\n", " return i, f, s, l, is_checked" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "bb5e0fa9574347c4ab79335485f825fd", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(FloatSlider(value=2.0, description='金利', max=5.0, min=1.0), IntSlider(value=20, descript…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.3:住宅ローンの返済シミュレータ\n", "from ipywidgets import IntSlider, FloatSlider\n", "import numpy as np\n", "\n", "rate_slider = FloatSlider(min=1, max=5, step=0.1, value=2, description=\"金利\")\n", "nper_slider = IntSlider(min=1, max=35, step=1, value=20, description=\"返済期間\")\n", "pv_slider = IntSlider(\n", " min=5000000, max=50000000, step=1000000, value=20000000, description=\"返済金額\"\n", ")\n", "\n", "\n", "@interact(rate=rate_slider, nper=nper_slider, pv=pv_slider)\n", "def pmt(rate, nper, pv):\n", " rate = rate * 0.01 / 12\n", " nper = nper * 12\n", " payment = abs(int(np.pmt(rate, nper, pv)))\n", " print(\"月々の返済額: {:,d} 円\".format(payment))\n", " print(\"総返済額: {:,d} 円\".format(payment * nper))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "# リストA.4:ウィジェット一覧\n", "from ipywidgets import Widget\n", "from pprint import pprint\n", "\n", "pprint(Widget.widget_types)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "cfb6bd98cace4f53b1cbdd9928cb4c51", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(description='いま何時?', style=ButtonStyle())" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.5:現在時刻を表示するボタン\n", "from ipywidgets import Button\n", "from IPython.display import display, clear_output\n", "from datetime import datetime\n", "\n", "\n", "def on_button_clicked(b):\n", " clear_output() # 既にある出力を削除\n", " print(\"{:%H時%M分%S秒}です\".format(datetime.now()))\n", "\n", "\n", "b = Button(description=\"いま何時?\")\n", "b.on_click(on_button_clicked)\n", "display(b)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "f5ea82fae96e4c5092cbf12d992e309c", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(HBox(children=(Text(value='Text'), Button(description='Button', style=ButtonStyle()))), HBox(ch…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.6:HBoxとVBoxを組み合わせて表示\n", "from ipywidgets import HBox, VBox, Text, Dropdown\n", "\n", "w1 = Text(value=\"Text\")\n", "w2 = Button(description=\"Button\")\n", "w3 = Dropdown(options=[\"1\", \"2\"])\n", "w4 = IntSlider()\n", "VBox([HBox([w1, w2]), HBox([w3, w4])])" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "34a8403ad526411c9c2d7db01e31d04c", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(Dropdown(options=('OVA', 'Movie', 'Special', 'TV', 'ONA', 'Music'), value='OVA'), Button(descri…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.7:Matplotlibとの連携\n", "import os\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "\n", "# サンプルデータの取得\n", "base_url = (\n", " \"https://raw.githubusercontent.com/practical-jupyter/sample-data/master/anime/\"\n", ")\n", "anime_genre_top10_csv = os.path.join(base_url, \"anime_genre_top10.csv\")\n", "top10_df = pd.read_csv(anime_genre_top10_csv)\n", "\n", "\n", "def plot_genre_members(b):\n", " clear_output()\n", " filter_by_type = top10_df.loc[top10_df[\"type\"] == types.value]\n", " plot_data = filter_by_type.groupby(\"genre\").sum()[\"members\"]\n", " ax = plot_data.plot.bar()\n", " ax.set_title(types.value)\n", " plt.show()\n", "\n", "\n", "types = Dropdown(options=list(top10_df[\"type\"].unique()))\n", "submit_button = Button(description=\"グラフを表示\")\n", "submit_button.on_click(plot_genre_members)\n", "HBox([types, submit_button])" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "445916b9f2f749e38f44ce90c3f50ae9", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Tab(children=(HBox(children=(ColorPicker(value='black', description='Movie color:'), FloatSlider(value=1.0, de…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " \n", " Loading BokehJS ...\n", "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "(function(global) {\n", " function now() {\n", " return new Date();\n", " }\n", "\n", " var force = true;\n", "\n", " if (typeof (window._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", " window._bokeh_onload_callbacks = [];\n", " window._bokeh_is_loading = undefined;\n", " }\n", "\n", "\n", " \n", " if (typeof (window._bokeh_timeout) === \"undefined\" || force === true) {\n", " window._bokeh_timeout = Date.now() + 5000;\n", " window._bokeh_failed_load = false;\n", " }\n", "\n", " var NB_LOAD_WARNING = {'data': {'text/html':\n", " \"
\\n\"+\n", " \"

\\n\"+\n", " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", " \"

\\n\"+\n", " \"\\n\"+\n", " \"\\n\"+\n", " \"from bokeh.resources import INLINE\\n\"+\n", " \"output_notebook(resources=INLINE)\\n\"+\n", " \"\\n\"+\n", " \"
\"}};\n", "\n", " function display_loaded() {\n", " if (window.Bokeh !== undefined) {\n", " var el = document.getElementById(\"2e1e66b5-d10b-4b72-9edd-8c97a7ca3a02\");\n", " el.textContent = \"BokehJS \" + Bokeh.version + \" successfully loaded.\";\n", " } else if (Date.now() < window._bokeh_timeout) {\n", " setTimeout(display_loaded, 100)\n", " }\n", " }\n", "\n", " function run_callbacks() {\n", " window._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", " delete window._bokeh_onload_callbacks\n", " console.info(\"Bokeh: all callbacks have finished\");\n", " }\n", "\n", " function load_libs(js_urls, callback) {\n", " window._bokeh_onload_callbacks.push(callback);\n", " if (window._bokeh_is_loading > 0) {\n", " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", " return null;\n", " }\n", " if (js_urls == null || js_urls.length === 0) {\n", " run_callbacks();\n", " return null;\n", " }\n", " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", " window._bokeh_is_loading = js_urls.length;\n", " for (var i = 0; i < js_urls.length; i++) {\n", " var url = js_urls[i];\n", " var s = document.createElement('script');\n", " s.src = url;\n", " s.async = false;\n", " s.onreadystatechange = s.onload = function() {\n", " window._bokeh_is_loading--;\n", " if (window._bokeh_is_loading === 0) {\n", " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", " run_callbacks()\n", " }\n", " };\n", " s.onerror = function() {\n", " console.warn(\"failed to load library \" + url);\n", " };\n", " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", " }\n", " };var element = document.getElementById(\"2e1e66b5-d10b-4b72-9edd-8c97a7ca3a02\");\n", " if (element == null) {\n", " console.log(\"Bokeh: ERROR: autoload.js configured with elementid '2e1e66b5-d10b-4b72-9edd-8c97a7ca3a02' but no matching script tag was found. \")\n", " return false;\n", " }\n", "\n", " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.5.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.5.min.js\"];\n", "\n", " var inline_js = [\n", " function(Bokeh) {\n", " Bokeh.set_log_level(\"info\");\n", " },\n", " \n", " function(Bokeh) {\n", " \n", " },\n", " \n", " function(Bokeh) {\n", " \n", " document.getElementById(\"2e1e66b5-d10b-4b72-9edd-8c97a7ca3a02\").textContent = \"BokehJS is loading...\";\n", "\n", " },\n", " function(Bokeh) {\n", " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.5.min.css\");\n", " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.5.min.css\");\n", " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.5.min.css\");\n", " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.5.min.css\");\n", " }\n", " ];\n", "\n", " function run_inline_js() {\n", " \n", " if ((window.Bokeh !== undefined) || (force === true)) {\n", " for (var i = 0; i < inline_js.length; i++) {\n", " inline_js[i](window.Bokeh);\n", " }if (force === true) {\n", " display_loaded();\n", " }} else if (Date.now() < window._bokeh_timeout) {\n", " setTimeout(run_inline_js, 100);\n", " } else if (!window._bokeh_failed_load) {\n", " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", " window._bokeh_failed_load = true;\n", " } else if (force !== true) {\n", " var cell = $(document.getElementById(\"2e1e66b5-d10b-4b72-9edd-8c97a7ca3a02\")).parents('.cell').data().cell;\n", " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", " }\n", "\n", " }\n", "\n", " if (window._bokeh_is_loading === 0) {\n", " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", " run_inline_js();\n", " } else {\n", " load_libs(js_urls, function() {\n", " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", " run_inline_js();\n", " });\n", " }\n", "}(this));" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リストA.8:Bokehとの連携\n", "from bokeh.plotting import figure\n", "from bokeh.io import output_notebook, push_notebook, show\n", "from bokeh.palettes import d3\n", "from IPython.display import display\n", "from ipywidgets import ColorPicker, Checkbox, Tab\n", "\n", "# 散布図を描画\n", "def plot_scatter(_type):\n", " data = df.loc[df[\"type\"] == _type, [\"members\", \"rating\"]]\n", " return p.circle(\n", " data[\"members\"],\n", " data[\"rating\"],\n", " legend=_type,\n", " color=colors[_type],\n", " line_color=None,\n", " )\n", "\n", "\n", "# 図形の色を変更\n", "def change_color(change):\n", " if change[\"new\"]:\n", " description = change[\"owner\"].description\n", " _type = description.split()[0]\n", " r[_type].glyph.fill_color = change[\"new\"]\n", " push_notebook(handle=t)\n", "\n", "\n", "# 図形の不透明度を変更\n", "def change_alpha(change):\n", " if change[\"new\"]:\n", " description = change[\"owner\"].description\n", " _type = description.split()[0]\n", " r[_type].glyph.fill_alpha = change[\"new\"]\n", " push_notebook(handle=t)\n", "\n", "\n", "# 図形の表示 ・ 非表示の切り替え\n", "def change_visible(change):\n", " description = change[\"owner\"].description\n", " _type = description.split()[0]\n", " r[_type].visible = change[\"new\"]\n", " push_notebook(handle=t)\n", "\n", "\n", "# サンプルデータの取得\n", "df = pd.read_csv(os.path.join(base_url, \"anime_master.csv\"))\n", "types = sorted(set(df[\"type\"])) # ユニークなtype列\n", "colors = dict(zip(types, d3[\"Category10\"][6])) # 配色\n", "# グラフの描画\n", "p = figure(plot_width=400, plot_height=400)\n", "r = dict(zip(types, [plot_scatter(x) for x in types]))\n", "p.legend.location = \"bottom_right\"\n", "# カラーピッカ\n", "color_picker = [ColorPicker(description=\" \".join((x, \"color:\"))) for x in types]\n", "# フロートスライダ\n", "float_slider = [\n", " FloatSlider(description=\" \".join((x, \"alpha:\")), min=0, max=1, value=1)\n", " for x in types\n", "]\n", "# チェックボックス\n", "check_box = [Checkbox(description=\" \".join((x, \"visible:\")), value=True) for x in types]\n", "# イベントのハンドリング\n", "for i, x in enumerate(types):\n", " color_picker[i].observe(change_color, names=\"value\")\n", " float_slider[i].observe(change_alpha, names=\"value\")\n", " check_box[i].observe(change_visible, names=\"value\")\n", "titles = dict(zip(range(len(types)), types)) # タブのタイトル\n", "# タブに登録するウィジェット\n", "children = [\n", " HBox([cp, fs, cb]) for cp, fs, cb in zip(color_picker, float_slider, check_box)\n", "]\n", "display(Tab(children=children, _titles=titles))\n", "output_notebook()\n", "t = show(p, notebook_handle=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.2" } }, "nbformat": 4, "nbformat_minor": 2 }