Created
January 27, 2017 21:53
-
-
Save aiguofer/927e9d71f6e1e8ea48ade18056ab3322 to your computer and use it in GitHub Desktop.
Bokeh 2 bar width
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:38.772864", | |
"start_time": "2017-01-27T21:44:37.995726" | |
}, | |
"collapsed": false, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"col": 0, | |
"height": 4, | |
"hidden": true, | |
"row": 4, | |
"width": 4 | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
}, | |
"scrolled": true | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"\n", | |
" <div class=\"bk-root\">\n", | |
" <a href=\"http://bokeh.pydata.org\" target=\"_blank\" class=\"bk-logo bk-logo-small bk-logo-notebook\"></a>\n", | |
" <span id=\"73f351c5-f0ce-423e-8e3d-693fb89fd1ed\">Loading BokehJS ...</span>\n", | |
" </div>" | |
] | |
}, | |
"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", | |
" \"<div style='background-color: #fdd'>\\n\"+\n", | |
" \"<p>\\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", | |
" \"</p>\\n\"+\n", | |
" \"<ul>\\n\"+\n", | |
" \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n", | |
" \"<li>use INLINE resources instead, as so:</li>\\n\"+\n", | |
" \"</ul>\\n\"+\n", | |
" \"<code>\\n\"+\n", | |
" \"from bokeh.resources import INLINE\\n\"+\n", | |
" \"output_notebook(resources=INLINE)\\n\"+\n", | |
" \"</code>\\n\"+\n", | |
" \"</div>\"}};\n", | |
"\n", | |
" function display_loaded() {\n", | |
" if (window.Bokeh !== undefined) {\n", | |
" document.getElementById(\"73f351c5-f0ce-423e-8e3d-693fb89fd1ed\").textContent = \"BokehJS 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(\"73f351c5-f0ce-423e-8e3d-693fb89fd1ed\");\n", | |
" if (element == null) {\n", | |
" console.log(\"Bokeh: ERROR: autoload.js configured with elementid '73f351c5-f0ce-423e-8e3d-693fb89fd1ed' 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.4.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.min.js\"];\n", | |
"\n", | |
" var inline_js = [\n", | |
" function(Bokeh) {\n", | |
" Bokeh.set_log_level(\"info\");\n", | |
" },\n", | |
" \n", | |
" function(Bokeh) {\n", | |
" \n", | |
" document.getElementById(\"73f351c5-f0ce-423e-8e3d-693fb89fd1ed\").textContent = \"BokehJS is loading...\";\n", | |
" },\n", | |
" function(Bokeh) {\n", | |
" console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.12.4.min.css\");\n", | |
" Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.12.4.min.css\");\n", | |
" console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.min.css\");\n", | |
" Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.12.4.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(\"73f351c5-f0ce-423e-8e3d-693fb89fd1ed\")).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" | |
} | |
], | |
"source": [ | |
"import pandas as pd\n", | |
"import numpy as np\n", | |
"\n", | |
"from bokeh.plotting import figure, show\n", | |
"from bokeh.io import output_notebook, push_notebook\n", | |
"from bokeh.layouts import layout\n", | |
"from bokeh.models import ColumnDataSource, CustomJS, DataRange1d, LinearAxis, Range1d, DateFormatter\n", | |
"from bokeh.models.widgets import DataTable, TableColumn\n", | |
"\n", | |
"from ipywidgets import interact\n", | |
"\n", | |
"output_notebook()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:38.836386", | |
"start_time": "2017-01-27T21:44:38.776933" | |
}, | |
"collapsed": true, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"hidden": true | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"ix = pd.date_range('2016-01-01', '2017-01-01', freq='d', name='date')\n", | |
"srs = pd.Series(np.random.randint(0, 300, size=len(ix)), index=ix, name='volume')\n", | |
"srs2 = pd.Series(np.random.randint(0, 1000, size=len(ix)), index=ix, name='size')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:39.003060", | |
"start_time": "2017-01-27T21:44:38.839259" | |
}, | |
"collapsed": false, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"col": 0, | |
"height": 14, | |
"hidden": false, | |
"row": 31, | |
"width": 6 | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"def get_data(freq='MS'):\n", | |
" return pd.DataFrame(srs.groupby(pd.Grouper(freq=freq)).sum())\n", | |
"\n", | |
"def get_data2(freq='MS'):\n", | |
" return pd.DataFrame(srs2.groupby(pd.Grouper(freq=freq)).sum())\n", | |
"\n", | |
"source = ColumnDataSource(data=ColumnDataSource.from_df(get_data()))\n", | |
"source_s = ColumnDataSource(data=ColumnDataSource.from_df(get_data() * .1))\n", | |
"\n", | |
"source2 = ColumnDataSource(data=ColumnDataSource.from_df(get_data2()))\n", | |
"\n", | |
"def get_width():\n", | |
" mindate = min(source.data['date'])\n", | |
" maxdate = max(source.data['date'])\n", | |
" return 0.8 * (maxdate-mindate).total_seconds() * 1000 / len(source.data['date'])\n", | |
"\n", | |
"f = figure(plot_width=550, plot_height=400, x_axis_type=\"datetime\", y_range=Range1d(0, max(source.data['volume']), bounds='auto'))\n", | |
"f.x_range.bounds='auto'\n", | |
"\n", | |
"f.extra_y_ranges = {\n", | |
" \"size\": Range1d(bounds='auto', start=0, end=max(source2.data['size'])),\n", | |
"}\n", | |
"\n", | |
"f.add_layout(LinearAxis(y_range_name='size'), 'right')\n", | |
"\n", | |
"r = f.vbar(source=source, top='volume', x='date', width=get_width())\n", | |
"r2 = f.vbar(source=source_s, top='volume', x='date', width=get_width(), color='green')\n", | |
"\n", | |
"f.line(source=source2, x='date', y='size', color='red', y_range_name='size')\n", | |
"f.tools[2].dimensions = 'width'" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:39.063805", | |
"start_time": "2017-01-27T21:44:39.005360" | |
}, | |
"collapsed": false, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"col": 6, | |
"height": 13, | |
"hidden": false, | |
"row": 31, | |
"width": 6 | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
}, | |
"scrolled": false | |
}, | |
"outputs": [], | |
"source": [ | |
"def get_data3(freq='MS'):\n", | |
" return pd.DataFrame(srs2.groupby(pd.Grouper(freq=freq)).mean())\n", | |
"\n", | |
"source3 = ColumnDataSource(data=ColumnDataSource.from_df(get_data3()))\n", | |
"\n", | |
"columns = [\n", | |
" TableColumn(field='date', formatter=DateFormatter(), title='date'),\n", | |
" TableColumn(field='size', title='size')\n", | |
"]\n", | |
"\n", | |
"t = DataTable(source=source3, columns=columns)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:39.322862", | |
"start_time": "2017-01-27T21:44:39.066104" | |
}, | |
"collapsed": false, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"col": 0, | |
"height": 29, | |
"hidden": false, | |
"row": 2, | |
"width": 12 | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
} | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"\n", | |
"\n", | |
" <div class=\"bk-root\">\n", | |
" <div class=\"bk-plotdiv\" id=\"d81ab5bb-4599-4283-bec6-3cfe0e833010\"></div>\n", | |
" </div>\n", | |
"<script type=\"text/javascript\">\n", | |
" \n", | |
" (function(global) {\n", | |
" function now() {\n", | |
" return new Date();\n", | |
" }\n", | |
" \n", | |
" var force = false;\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() + 0;\n", | |
" window._bokeh_failed_load = false;\n", | |
" }\n", | |
" \n", | |
" var NB_LOAD_WARNING = {'data': {'text/html':\n", | |
" \"<div style='background-color: #fdd'>\\n\"+\n", | |
" \"<p>\\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", | |
" \"</p>\\n\"+\n", | |
" \"<ul>\\n\"+\n", | |
" \"<li>re-rerun `output_notebook()` to attempt to load from CDN again, or</li>\\n\"+\n", | |
" \"<li>use INLINE resources instead, as so:</li>\\n\"+\n", | |
" \"</ul>\\n\"+\n", | |
" \"<code>\\n\"+\n", | |
" \"from bokeh.resources import INLINE\\n\"+\n", | |
" \"output_notebook(resources=INLINE)\\n\"+\n", | |
" \"</code>\\n\"+\n", | |
" \"</div>\"}};\n", | |
" \n", | |
" function display_loaded() {\n", | |
" if (window.Bokeh !== undefined) {\n", | |
" document.getElementById(\"d81ab5bb-4599-4283-bec6-3cfe0e833010\").textContent = \"BokehJS successfully loaded.\";\n", | |
" } else if (Date.now() < window._bokeh_timeout) {\n", | |
" setTimeout(display_loaded, 100)\n", | |
" }\n", | |
" }if ((window.Jupyter !== undefined) && Jupyter.notebook.kernel) {\n", | |
" comm_manager = Jupyter.notebook.kernel.comm_manager\n", | |
" comm_manager.register_target(\"4d73b9e0-1f5a-455e-82b2-c344e733195f\", function () {});\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(\"d81ab5bb-4599-4283-bec6-3cfe0e833010\");\n", | |
" if (element == null) {\n", | |
" console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'd81ab5bb-4599-4283-bec6-3cfe0e833010' but no matching script tag was found. \")\n", | |
" return false;\n", | |
" }\n", | |
" \n", | |
" var js_urls = [];\n", | |
" \n", | |
" var inline_js = [\n", | |
" function(Bokeh) {\n", | |
" (function() {\n", | |
" var fn = function() {\n", | |
" var docs_json = {\"a1c30966-87f6-41cc-9cfa-bd657f03dc4e\":{\"roots\":{\"references\":[{\"attributes\":{\"line_color\":{\"value\":\"red\"},\"x\":{\"field\":\"date\"},\"y\":{\"field\":\"size\"}},\"id\":\"61c7709e-99a8-4a92-9a5f-b17d4e314a51\",\"type\":\"Line\"},{\"attributes\":{\"months\":[0,1,2,3,4,5,6,7,8,9,10,11]},\"id\":\"c7bbadd4-7d72-4e41-8b67-5aa9d45f3f25\",\"type\":\"MonthsTicker\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"22eff53d-0291-4990-950f-d0791d5daa65\",\"type\":\"PanTool\"},{\"attributes\":{\"base\":24,\"mantissas\":[1,2,4,6,8,12],\"max_interval\":43200000.0,\"min_interval\":3600000.0,\"num_minor_ticks\":0},\"id\":\"ff5df074-4366-4945-a4fc-e0791bc79474\",\"type\":\"AdaptiveTicker\"},{\"attributes\":{\"dimensions\":\"width\",\"overlay\":{\"id\":\"e3c39765-946c-4bb3-9274-68a507b50bd0\",\"type\":\"BoxAnnotation\"},\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"1ef6c1ad-23a6-497a-8481-f06823c03b36\",\"type\":\"BoxZoomTool\"},{\"attributes\":{},\"id\":\"109d25b5-718a-4325-9549-87355ffe80ea\",\"type\":\"ToolEvents\"},{\"attributes\":{\"bounds\":\"auto\",\"callback\":null,\"end\":16587},\"id\":\"cd11f857-4a3b-456f-848d-fdc20db85272\",\"type\":\"Range1d\"},{\"attributes\":{},\"id\":\"6ebc60ee-6450-418a-997a-edfaa9ff72dc\",\"type\":\"YearsTicker\"},{\"attributes\":{},\"id\":\"42a4f02e-755c-4e32-a0e9-4c5aa0d0ec1c\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"editor\":{\"id\":\"90a221cf-e914-42c5-a41f-c63db17e43ba\",\"type\":\"StringEditor\"},\"field\":\"date\",\"formatter\":{\"id\":\"115dbb21-2d9b-43d5-92a8-2143e031e66b\",\"type\":\"DateFormatter\"},\"title\":\"date\"},\"id\":\"721633f5-99ef-4001-a080-9b259b2a3d5c\",\"type\":\"TableColumn\"},{\"attributes\":{\"bounds\":\"auto\",\"callback\":null,\"end\":4849},\"id\":\"702b2e54-2a0d-4b54-884a-b1ed7ba993ad\",\"type\":\"Range1d\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"date\",\"size\"],\"data\":{\"date\":[1451606400000.0,1454284800000.0,1456790400000.0,1459468800000.0,1462060800000.0,1464739200000.0,1467331200000.0,1470009600000.0,1472688000000.0,1475280000000.0,1477958400000.0,1480550400000.0,1483228800000.0],\"size\":[411.5806451612903,559.6206896551724,511.2903225806452,403.7,535.0645161290323,488.1666666666667,470.4193548387097,486.80645161290323,500.3333333333333,518.516129032258,517.4,524.6129032258065,558.0]}},\"id\":\"6fd51e8e-66cc-4964-bacb-4f2285352e1d\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"bottom_units\":\"screen\",\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"render_mode\":\"css\",\"right_units\":\"screen\",\"top_units\":\"screen\"},\"id\":\"e3c39765-946c-4bb3-9274-68a507b50bd0\",\"type\":\"BoxAnnotation\"},{\"attributes\":{},\"id\":\"36bea229-e758-47b9-82be-b6d128a5186c\",\"type\":\"StringEditor\"},{\"attributes\":{\"data_source\":{\"id\":\"7aa0c254-3b04-4042-ae99-e7f08a227866\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"39a391cf-465c-4e99-a30b-3a457bd637f3\",\"type\":\"VBar\"},\"hover_glyph\":null,\"nonselection_glyph\":{\"id\":\"5d42d1b2-2758-4d51-81a6-3b1137f36188\",\"type\":\"VBar\"},\"selection_glyph\":null},\"id\":\"148069c0-4d65-49bb-8fcc-85db9dd8152b\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"82d051e5-156f-4f24-a530-17a80a67da0b\",\"type\":\"StringFormatter\"},{\"attributes\":{},\"id\":\"90a221cf-e914-42c5-a41f-c63db17e43ba\",\"type\":\"StringEditor\"},{\"attributes\":{\"data_source\":{\"id\":\"cf505e44-6209-4c83-97cb-c6786ceb5602\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"61c7709e-99a8-4a92-9a5f-b17d4e314a51\",\"type\":\"Line\"},\"hover_glyph\":null,\"nonselection_glyph\":{\"id\":\"ca0ebb2c-bc2e-408a-9c70-271015de2a37\",\"type\":\"Line\"},\"selection_glyph\":null,\"y_range_name\":\"size\"},\"id\":\"699dd15b-6383-40b8-8cef-645fb18e2230\",\"type\":\"GlyphRenderer\"},{\"attributes\":{\"below\":[{\"id\":\"d2b7f6ba-046e-4f05-a466-6f1485f8d6ed\",\"type\":\"DatetimeAxis\"}],\"extra_y_ranges\":{\"size\":{\"id\":\"cd11f857-4a3b-456f-848d-fdc20db85272\",\"type\":\"Range1d\"}},\"left\":[{\"id\":\"b197f6a4-774c-4b34-89d6-5c1492bfb92c\",\"type\":\"LinearAxis\"}],\"plot_height\":400,\"plot_width\":550,\"renderers\":[{\"id\":\"d2b7f6ba-046e-4f05-a466-6f1485f8d6ed\",\"type\":\"DatetimeAxis\"},{\"id\":\"5751f38f-92fe-4def-b85b-3e7cd8f20ecc\",\"type\":\"Grid\"},{\"id\":\"b197f6a4-774c-4b34-89d6-5c1492bfb92c\",\"type\":\"LinearAxis\"},{\"id\":\"bb8a9451-3585-4cec-a174-b418ea776746\",\"type\":\"Grid\"},{\"id\":\"e3c39765-946c-4bb3-9274-68a507b50bd0\",\"type\":\"BoxAnnotation\"},{\"id\":\"74dc3f04-7a77-4b60-86ad-0e40f4d80d36\",\"type\":\"LinearAxis\"},{\"id\":\"148069c0-4d65-49bb-8fcc-85db9dd8152b\",\"type\":\"GlyphRenderer\"},{\"id\":\"9336aac1-f0ed-4fe9-8acb-a78bba388bb5\",\"type\":\"GlyphRenderer\"},{\"id\":\"699dd15b-6383-40b8-8cef-645fb18e2230\",\"type\":\"GlyphRenderer\"}],\"right\":[{\"id\":\"74dc3f04-7a77-4b60-86ad-0e40f4d80d36\",\"type\":\"LinearAxis\"}],\"title\":{\"id\":\"07d988b8-7817-4700-97be-3be11aec63d9\",\"type\":\"Title\"},\"tool_events\":{\"id\":\"109d25b5-718a-4325-9549-87355ffe80ea\",\"type\":\"ToolEvents\"},\"toolbar\":{\"id\":\"a84cb3e7-026d-429f-a2c5-6257a8678038\",\"type\":\"Toolbar\"},\"x_range\":{\"id\":\"e0e600a3-0b53-4554-a8d3-34e0acde96a8\",\"type\":\"DataRange1d\"},\"y_range\":{\"id\":\"702b2e54-2a0d-4b54-884a-b1ed7ba993ad\",\"type\":\"Range1d\"}},\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{},\"id\":\"7a41d4b6-10fc-472a-9d3f-18e5af3a0a5d\",\"type\":\"DatetimeTickFormatter\"},{\"attributes\":{\"formatter\":{\"id\":\"ebb1e44b-3cf9-42b1-a79e-e1b3b631cb81\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"e4abcdc4-969d-40b4-a9fe-602d6826e353\",\"type\":\"BasicTicker\"}},\"id\":\"b197f6a4-774c-4b34-89d6-5c1492bfb92c\",\"type\":\"LinearAxis\"},{\"attributes\":{\"data_source\":{\"id\":\"733fd20f-c65a-4c39-a06c-b053a5767671\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"ea29aa25-6c96-40ad-baf1-66366ab81316\",\"type\":\"VBar\"},\"hover_glyph\":null,\"nonselection_glyph\":{\"id\":\"08cda360-e432-4ddf-ac44-0ec8e12385c0\",\"type\":\"VBar\"},\"selection_glyph\":null},\"id\":\"9336aac1-f0ed-4fe9-8acb-a78bba388bb5\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"ebb1e44b-3cf9-42b1-a79e-e1b3b631cb81\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"formatter\":{\"id\":\"42a4f02e-755c-4e32-a0e9-4c5aa0d0ec1c\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"55ad2592-08d9-477c-95bd-578a00db590d\",\"type\":\"BasicTicker\"},\"y_range_name\":\"size\"},\"id\":\"74dc3f04-7a77-4b60-86ad-0e40f4d80d36\",\"type\":\"LinearAxis\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"volume\",\"date\"],\"data\":{\"date\":[1451606400000.0,1454284800000.0,1456790400000.0,1459468800000.0,1462060800000.0,1464739200000.0,1467331200000.0,1470009600000.0,1472688000000.0,1475280000000.0,1477958400000.0,1480550400000.0,1483228800000.0],\"volume\":[4668,4309,4419,4573,4293,4138,4445,4549,4007,4842,4836,4849,286]}},\"id\":\"7aa0c254-3b04-4042-ae99-e7f08a227866\",\"type\":\"ColumnDataSource\"},{\"attributes\":{},\"id\":\"55ad2592-08d9-477c-95bd-578a00db590d\",\"type\":\"BasicTicker\"},{\"attributes\":{\"days\":[1,4,7,10,13,16,19,22,25,28]},\"id\":\"dd6f5e04-75f8-48dc-9e2d-34e95ed63fd9\",\"type\":\"DaysTicker\"},{\"attributes\":{\"fill_color\":{\"value\":\"#1f77b4\"},\"line_color\":{\"value\":\"#1f77b4\"},\"top\":{\"field\":\"volume\"},\"width\":{\"value\":1945993846.1538465},\"x\":{\"field\":\"date\"}},\"id\":\"39a391cf-465c-4e99-a30b-3a457bd637f3\",\"type\":\"VBar\"},{\"attributes\":{\"days\":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]},\"id\":\"8a8e24ee-ab6d-429b-808b-a717a64530c6\",\"type\":\"DaysTicker\"},{\"attributes\":{},\"id\":\"115dbb21-2d9b-43d5-92a8-2143e031e66b\",\"type\":\"DateFormatter\"},{\"attributes\":{\"months\":[0,6]},\"id\":\"ad862930-50c5-49ca-a97c-cff335153f52\",\"type\":\"MonthsTicker\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"d30c54a9-f0c0-4b0b-8981-a27cd85de3c6\",\"type\":\"SaveTool\"},{\"attributes\":{\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"date\"},\"y\":{\"field\":\"size\"}},\"id\":\"ca0ebb2c-bc2e-408a-9c70-271015de2a37\",\"type\":\"Line\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"ff8dcaeb-39cf-4029-9067-ba7c0fdd702c\",\"type\":\"HelpTool\"},{\"attributes\":{},\"id\":\"e4abcdc4-969d-40b4-a9fe-602d6826e353\",\"type\":\"BasicTicker\"},{\"attributes\":{\"base\":60,\"mantissas\":[1,2,5,10,15,20,30],\"max_interval\":1800000.0,\"min_interval\":1000.0,\"num_minor_ticks\":0},\"id\":\"7e16968e-ed63-4cd5-829a-4ffa1ffa0b90\",\"type\":\"AdaptiveTicker\"},{\"attributes\":{\"months\":[0,2,4,6,8,10]},\"id\":\"5289f89d-2270-4f6f-b3b9-a20e5b148cbc\",\"type\":\"MonthsTicker\"},{\"attributes\":{\"max_interval\":500.0,\"num_minor_ticks\":0},\"id\":\"01ec447e-2e2f-4e13-baf3-7b0bcb515d2c\",\"type\":\"AdaptiveTicker\"},{\"attributes\":{\"children\":[{\"id\":\"35777c00-df31-4167-9702-35c9c73e6898\",\"type\":\"WidgetBox\"}]},\"id\":\"1aac2fcf-c7e9-4704-81c3-48d11d3f7aee\",\"type\":\"Row\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.1},\"fill_color\":{\"value\":\"#1f77b4\"},\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"top\":{\"field\":\"volume\"},\"width\":{\"value\":1945993846.1538465},\"x\":{\"field\":\"date\"}},\"id\":\"08cda360-e432-4ddf-ac44-0ec8e12385c0\",\"type\":\"VBar\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"6bc89f93-3f4c-4dca-b984-fd683e0c177f\",\"type\":\"ResetTool\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.1},\"fill_color\":{\"value\":\"#1f77b4\"},\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"top\":{\"field\":\"volume\"},\"width\":{\"value\":1945993846.1538465},\"x\":{\"field\":\"date\"}},\"id\":\"5d42d1b2-2758-4d51-81a6-3b1137f36188\",\"type\":\"VBar\"},{\"attributes\":{\"fill_color\":{\"value\":\"green\"},\"line_color\":{\"value\":\"green\"},\"top\":{\"field\":\"volume\"},\"width\":{\"value\":1945993846.1538465},\"x\":{\"field\":\"date\"}},\"id\":\"ea29aa25-6c96-40ad-baf1-66366ab81316\",\"type\":\"VBar\"},{\"attributes\":{\"days\":[1,15]},\"id\":\"8b8de9e2-ee71-466b-ba31-1e6b33e4a9b1\",\"type\":\"DaysTicker\"},{\"attributes\":{\"dimension\":1,\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"e4abcdc4-969d-40b4-a9fe-602d6826e353\",\"type\":\"BasicTicker\"}},\"id\":\"bb8a9451-3585-4cec-a174-b418ea776746\",\"type\":\"Grid\"},{\"attributes\":{\"children\":[{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}]},\"id\":\"fa27a16b-f7bf-44e7-851e-691b97c60817\",\"type\":\"Row\"},{\"attributes\":{\"columns\":[{\"id\":\"721633f5-99ef-4001-a080-9b259b2a3d5c\",\"type\":\"TableColumn\"},{\"id\":\"b84d3848-d03a-48ce-add6-fa4aaaae302f\",\"type\":\"TableColumn\"}],\"source\":{\"id\":\"6fd51e8e-66cc-4964-bacb-4f2285352e1d\",\"type\":\"ColumnDataSource\"}},\"id\":\"275ee8f9-7c85-4e70-a11a-64e7f72b69ae\",\"type\":\"DataTable\"},{\"attributes\":{\"children\":[{\"id\":\"275ee8f9-7c85-4e70-a11a-64e7f72b69ae\",\"type\":\"DataTable\"}],\"height\":400},\"id\":\"35777c00-df31-4167-9702-35c9c73e6898\",\"type\":\"WidgetBox\"},{\"attributes\":{\"formatter\":{\"id\":\"7a41d4b6-10fc-472a-9d3f-18e5af3a0a5d\",\"type\":\"DatetimeTickFormatter\"},\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"18c2bbdc-6566-48c3-97c1-99f208a157b1\",\"type\":\"DatetimeTicker\"}},\"id\":\"d2b7f6ba-046e-4f05-a466-6f1485f8d6ed\",\"type\":\"DatetimeAxis\"},{\"attributes\":{\"bounds\":\"auto\",\"callback\":null},\"id\":\"e0e600a3-0b53-4554-a8d3-34e0acde96a8\",\"type\":\"DataRange1d\"},{\"attributes\":{\"days\":[1,8,15,22]},\"id\":\"6e21cd16-b054-4f52-b9ef-58e3687c8523\",\"type\":\"DaysTicker\"},{\"attributes\":{\"plot\":null,\"text\":\"\"},\"id\":\"07d988b8-7817-4700-97be-3be11aec63d9\",\"type\":\"Title\"},{\"attributes\":{\"children\":[{\"id\":\"fa27a16b-f7bf-44e7-851e-691b97c60817\",\"type\":\"Row\"},{\"id\":\"1aac2fcf-c7e9-4704-81c3-48d11d3f7aee\",\"type\":\"Row\"}]},\"id\":\"63be2749-429b-41bd-95d1-94e3fe618105\",\"type\":\"Column\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"volume\",\"date\"],\"data\":{\"date\":[1451606400000.0,1454284800000.0,1456790400000.0,1459468800000.0,1462060800000.0,1464739200000.0,1467331200000.0,1470009600000.0,1472688000000.0,1475280000000.0,1477958400000.0,1480550400000.0,1483228800000.0],\"volume\":[466.8,430.90000000000003,441.90000000000003,457.3,429.3,413.8,444.5,454.90000000000003,400.70000000000005,484.20000000000005,483.6,484.90000000000003,28.6]}},\"id\":\"733fd20f-c65a-4c39-a06c-b053a5767671\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"18c2bbdc-6566-48c3-97c1-99f208a157b1\",\"type\":\"DatetimeTicker\"}},\"id\":\"5751f38f-92fe-4def-b85b-3e7cd8f20ecc\",\"type\":\"Grid\"},{\"attributes\":{\"callback\":null,\"column_names\":[\"date\",\"size\"],\"data\":{\"date\":[1451606400000.0,1454284800000.0,1456790400000.0,1459468800000.0,1462060800000.0,1464739200000.0,1467331200000.0,1470009600000.0,1472688000000.0,1475280000000.0,1477958400000.0,1480550400000.0,1483228800000.0],\"size\":[12759,16229,15850,12111,16587,14645,14583,15091,15010,16074,15522,16263,558]}},\"id\":\"cf505e44-6209-4c83-97cb-c6786ceb5602\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"num_minor_ticks\":5},\"id\":\"18c2bbdc-6566-48c3-97c1-99f208a157b1\",\"type\":\"DatetimeTicker\"},{\"attributes\":{\"months\":[0,4,8]},\"id\":\"dff93403-e0d4-42de-8a1d-9f91f6aa9a04\",\"type\":\"MonthsTicker\"},{\"attributes\":{\"active_drag\":\"auto\",\"active_scroll\":\"auto\",\"active_tap\":\"auto\",\"tools\":[{\"id\":\"22eff53d-0291-4990-950f-d0791d5daa65\",\"type\":\"PanTool\"},{\"id\":\"742dc246-0bdc-4193-8458-4b68c32f121c\",\"type\":\"WheelZoomTool\"},{\"id\":\"1ef6c1ad-23a6-497a-8481-f06823c03b36\",\"type\":\"BoxZoomTool\"},{\"id\":\"d30c54a9-f0c0-4b0b-8981-a27cd85de3c6\",\"type\":\"SaveTool\"},{\"id\":\"6bc89f93-3f4c-4dca-b984-fd683e0c177f\",\"type\":\"ResetTool\"},{\"id\":\"ff8dcaeb-39cf-4029-9067-ba7c0fdd702c\",\"type\":\"HelpTool\"}]},\"id\":\"a84cb3e7-026d-429f-a2c5-6257a8678038\",\"type\":\"Toolbar\"},{\"attributes\":{\"editor\":{\"id\":\"36bea229-e758-47b9-82be-b6d128a5186c\",\"type\":\"StringEditor\"},\"field\":\"size\",\"formatter\":{\"id\":\"82d051e5-156f-4f24-a530-17a80a67da0b\",\"type\":\"StringFormatter\"},\"title\":\"size\"},\"id\":\"b84d3848-d03a-48ce-add6-fa4aaaae302f\",\"type\":\"TableColumn\"},{\"attributes\":{\"plot\":{\"id\":\"9a406b62-80d2-4237-8bb6-0e9ff10d5a62\",\"subtype\":\"Figure\",\"type\":\"Plot\"}},\"id\":\"742dc246-0bdc-4193-8458-4b68c32f121c\",\"type\":\"WheelZoomTool\"}],\"root_ids\":[\"63be2749-429b-41bd-95d1-94e3fe618105\"]},\"title\":\"Bokeh Application\",\"version\":\"0.12.4\"}};\n", | |
" var render_items = [{\"docid\":\"a1c30966-87f6-41cc-9cfa-bd657f03dc4e\",\"elementid\":\"d81ab5bb-4599-4283-bec6-3cfe0e833010\",\"modelid\":\"63be2749-429b-41bd-95d1-94e3fe618105\",\"notebook_comms_target\":\"4d73b9e0-1f5a-455e-82b2-c344e733195f\"}];\n", | |
" \n", | |
" Bokeh.embed.embed_items(docs_json, render_items);\n", | |
" };\n", | |
" if (document.readyState != \"loading\") fn();\n", | |
" else document.addEventListener(\"DOMContentLoaded\", fn);\n", | |
" })();\n", | |
" },\n", | |
" function(Bokeh) {\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(\"d81ab5bb-4599-4283-bec6-3cfe0e833010\")).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));\n", | |
"</script>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"all_handle = show(layout([[f], [t]]), notebook_handle=True)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2017-01-27T21:44:39.405397", | |
"start_time": "2017-01-27T21:44:39.325434" | |
}, | |
"collapsed": false, | |
"extensions": { | |
"jupyter_dashboards": { | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"col": 0, | |
"height": 2, | |
"hidden": false, | |
"row": 0, | |
"width": 12 | |
}, | |
"report_default": { | |
"hidden": false | |
} | |
} | |
} | |
} | |
}, | |
"outputs": [], | |
"source": [ | |
"def update_data(freq={'Quarter': 'QS', 'Month': 'MS', 'Week': 'W'}):\n", | |
" source.data = ColumnDataSource.from_df(get_data(freq))\n", | |
" source2.data = ColumnDataSource.from_df(get_data2(freq))\n", | |
" source_s.data = ColumnDataSource.from_df(get_data(freq) * .1)\n", | |
"\n", | |
" r.glyph.width = get_width()\n", | |
" r2.glyph.width = get_width()\n", | |
"\n", | |
" f.y_range.end = max(source.data['volume'])\n", | |
" f.extra_y_ranges['size'].end = max(source2.data['size'])\n", | |
"\n", | |
" source3.data = ColumnDataSource.from_df(get_data3(freq))\n", | |
" push_notebook(handle=all_handle)\n", | |
" \n", | |
"i = interact(update_data)" | |
] | |
} | |
], | |
"metadata": { | |
"extensions": { | |
"jupyter_dashboards": { | |
"activeView": "grid_default", | |
"version": 1, | |
"views": { | |
"grid_default": { | |
"cellMargin": 10, | |
"defaultCellHeight": 20, | |
"layoutStrategy": "packed", | |
"maxColumns": 12, | |
"name": "grid", | |
"type": "grid" | |
}, | |
"report_default": { | |
"name": "report", | |
"type": "report" | |
} | |
} | |
} | |
}, | |
"hide_input": false, | |
"kernelspec": { | |
"display_name": "Python 2", | |
"language": "python", | |
"name": "python2" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.5" | |
}, | |
"widgets": { | |
"state": { | |
"559617694675468e81d396f84a834955": { | |
"views": [ | |
{ | |
"cell_index": 5 | |
} | |
] | |
} | |
}, | |
"version": "1.2.0" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment