{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## 第6章 Bokehでグラフを描画しよう\n", "\n", "### 6-6: 棒グラフ" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "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(\"340952e7-e22c-4dde-b862-adb4c4071cb1\");\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(\"340952e7-e22c-4dde-b862-adb4c4071cb1\");\n", " if (element == null) {\n", " console.log(\"Bokeh: ERROR: autoload.js configured with elementid '340952e7-e22c-4dde-b862-adb4c4071cb1' 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(\"340952e7-e22c-4dde-b862-adb4c4071cb1\").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(\"340952e7-e22c-4dde-b862-adb4c4071cb1\")).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": [ "# リスト6.6.1:リスト-ライク・オブジェクトのデータを渡したグラフ\n", "from bokeh.charts import output_notebook, Bar, show\n", "\n", "output_notebook()\n", "p = Bar([1, 2, 3], plot_width=300, plot_height=200)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.2:辞書型のデータを渡したグラフ\n", "data = {\"data\": [1, 2, 3], \"x_label\": [\"a\", \"b\", \"c\"]}\n", "p = Bar(data, values=\"data\", label=\"x_label\", plot_width=300, plot_height=200)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.3:DataFrameを渡したグラフ\n", "import os\n", "import pandas as pd\n", "\n", "base_url = (\n", " \"https://raw.githubusercontent.com/practical-jupyter/sample-data/master/anime/\"\n", ")\n", "anime_master_csv = os.path.join(base_url, \"anime_master.csv\")\n", "df = pd.read_csv(anime_master_csv)\n", "sum_df = df.groupby(\"type\").sum()\n", "p = Bar(\n", " sum_df,\n", " values=\"members\",\n", " ylabel=\"メンバ数の合計\",\n", " plot_width=400,\n", " plot_height=400,\n", " legend=False,\n", ") # 凡例を非表示\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.4:indexをX軸としたグラフ\n", "p = Bar(\n", " sum_df.reset_index(),\n", " label=\"type\",\n", " values=\"members\",\n", " ylabel=\"メンバ数の合計\",\n", " plot_width=400,\n", " plot_height=400,\n", " legend=False,\n", ")\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.5:Bokehの集約機能を使用したグラフ\n", "p = Bar(\n", " df,\n", " label=\"type\",\n", " values=\"members\",\n", " agg=\"sum\",\n", " ylabel=\"メンバ数の合計\",\n", " plot_width=400,\n", " plot_height=400,\n", " legend=False,\n", ")\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.6:グループ化したグラフ\n", "top10_df = pd.read_csv(os.path.join(base_url, \"anime_genre_top10.csv\"))\n", "p = Bar(\n", " top10_df,\n", " label=\"genre\",\n", " values=\"members\",\n", " group=\"type\",\n", " agg=\"sum\",\n", " ylabel=\"メンバ数の合計\",\n", " plot_width=600,\n", " plot_height=400,\n", " legend=\"top_right\",\n", ") # 凡例の位置\n", "p.legend.background_fill_alpha = 0 # 凡例の背景を透過 (次章参照)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.7:積み上げ棒グラフ\n", "p = Bar(\n", " top10_df.sort_values(\"type\"),\n", " label=\"genre\",\n", " values=\"members\",\n", " stack=\"type\",\n", " agg=\"sum\",\n", " ylabel=\"メンバ数の合計\",\n", " plot_width=600,\n", " plot_height=400,\n", " legend=\"top_right\",\n", ")\n", "p.legend.padding = 0 # 凡例の中の余白を設定 (次章参照)\n", "p.legend.background_fill_alpha = 0 # 凡例の背景を透過 (次章参照)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.8:vbar()メソッドを使用した棒グラフ\n", "from bokeh.plotting import figure\n", "\n", "p = figure(plot_width=200, plot_height=200)\n", "p.vbar(x=[1, 2, 3], top=[1, 2, 3], width=0.5)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.9:hbar()メソッドを使用した棒グラフ\n", "p = figure(plot_width=200, plot_height=200)\n", "p.hbar(y=[1, 2, 3], right=[1, 2, 3], height=0.5)\n", "show(p)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "
\n", "
\n", "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# リスト6.6.10:書式を設定した棒グラフ\n", "from bokeh.palettes import d3\n", "\n", "# ジャンルをメンバ数で集計\n", "genre = top10_df.groupby(\"genre\")[\"members\"].sum().sort_values()\n", "p = figure(\n", " title=\"メンバ数が多いジャンルトップ10\",\n", " plot_width=400,\n", " plot_height=400,\n", " x_range=(0, genre.max()),\n", " y_range=(-0.5, len(genre) - 0.5),\n", ")\n", "text_x = genre.min() * 0.1 # 注釈のX座標\n", "colors = d3[\"Category20b\"][10][::-1] # カラーパレット(7章で解説)\n", "# 枠、 罫線、 軸をすべて非表示\n", "p.outline_line_color = None\n", "p.grid.visible = False\n", "p.axis.visible = False\n", "for i, g in enumerate(genre):\n", " text = \": \".join((genre.index[i], \"{:,}\".format(g)))\n", " p.hbar(y=i, left=0, right=g, height=1, color=colors[i])\n", " p.text(\n", " x=text_x,\n", " y=i,\n", " text=[text],\n", " text_color=\"#ffffff\",\n", " text_font_size=\"10pt\",\n", " text_font_style=\"bold\",\n", " text_baseline=\"middle\",\n", " )\n", "show(p)" ] }, { "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 }