{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# bqplot: complex interactive visualizations\n", "\n", "## https://github.com/bloomberg/bqplot\n", "\n", "## A Jupyter - d3.js bridge\n", "\n", "bqplot is a jupyter interactive widget library bringing d3.js visualization to the Jupyter notebook.\n", "\n", "- Apache Licensed\n", "\n", "bqplot implements the abstractions of Wilkinson’s “The Grammar of Graphics” as interactive Jupyter widgets.\n", "\n", "bqplot provides both\n", "-\thigh-level plotting procedures with relevant defaults for common chart types,\n", "-\tlower-level descriptions of data visualizations meant for complex interactive visualization dashboards and applications involving mouse interactions and user-provided Python callbacks.\n", "\n", "**Installation:**\n", "\n", "```bash\n", "conda install -c conda-forge bqplot\n", "```" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from __future__ import print_function\n", "from IPython.display import display\n", "from ipywidgets import *\n", "from traitlets import *\n", "\n", "import numpy as np\n", "import pandas as pd\n", "import bqplot as bq\n", "import datetime as dt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "np.random.seed(0)\n", "size = 100\n", "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", "y_data_2 = np.cumsum(np.random.randn(size))\n", "y_data_3 = np.cumsum(np.random.randn(size) * 100.)\n", "\n", "x = np.linspace(0.0, 10.0, size)\n", "\n", "price_data = pd.DataFrame(np.cumsum(np.random.randn(150, 2).dot([[0.5, 0.8], [0.8, 1.0]]), axis=0) + 100,\n", " columns=['Security 1', 'Security 2'],\n", " index=pd.date_range(start='01-01-2007', periods=150))\n", "\n", "symbol = 'Security 1'\n", "dates_all = price_data.index.values\n", "final_prices = price_data[symbol].values.flatten()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# A simple plot with the pyplot API" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from bqplot import pyplot as plt" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "ce93314362854c96901f3f0144bc57a3", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(1)\n", "n = 100\n", "plt.plot(np.linspace(0.0, 10.0, n), np.cumsum(np.random.randn(n)), \n", " axes_options={'y': {'grid_lines': 'dashed'}})\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scatter Plot" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "9475b0c975424d7b854c6ffdb02b5646", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(title='Scatter Plot with colors')\n", "plt.scatter(y_data_2, y_data_3, color=y_data)\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Histogram" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e46996f4fdcb428e8949213c4d550491", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure()\n", "plt.hist(y_data, colors=['OrangeRed'])\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Every component of the figure is an independent widget" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "0cdfaeb7eb3a436a9a54d0c3c9334e51", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "xs = bq.LinearScale()\n", "ys = bq.LinearScale()\n", "x = np.arange(100)\n", "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", "\n", "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", "\n", "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000)\n", "display(fig)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# update data of the line mark\n", "line.y = np.cumsum(np.random.randn(2, 100), axis=1)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "08906a17e54945cca701750e553e0bd2", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "xs = bq.LinearScale()\n", "ys = bq.LinearScale()\n", "x, y = np.random.rand(2, 20)\n", "scatt = bq.Scatter(x=x, y=y, scales={'x': xs, 'y': ys}, default_colors=['blue'])\n", "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')\n", "\n", "fig = bq.Figure(marks=[scatt], axes=[xax, yax], animation_duration=1000)\n", "display(fig)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "#data updates\n", "scatt.x = np.random.rand(20) * 10\n", "scatt.y = np.random.rand(20)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The same holds for the attributes of scales, axes" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xs.min = 4" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xs.min = None" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xax.label = 'Some label for the x axis'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use bqplot figures as input widgets" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xs = bq.LinearScale()\n", "ys = bq.LinearScale()\n", "x = np.arange(100)\n", "y = np.cumsum(np.random.randn(2, 100), axis=1) #two random walks\n", "\n", "line = bq.Lines(x=x, y=y, scales={'x': xs, 'y': ys}, colors=['red', 'green'])\n", "xax = bq.Axis(scale=xs, label='x', grid_lines='solid')\n", "yax = bq.Axis(scale=ys, orientation='vertical', tick_format='0.2f', label='y', grid_lines='solid')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Selections" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "fc18c480beaa4abfa8642e8636ff0b08", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def interval_change_callback(change):\n", " db.value = str(change['new'])\n", "\n", "intsel = bq.interacts.FastIntervalSelector(scale=xs, marks=[line])\n", "intsel.observe(interval_change_callback, names=['selected'] )\n", "\n", "db = widgets.Label()\n", "db.value = str(intsel.selected)\n", "display(db)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "7c5241acd5b244aabdc12964899dd480", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = bq.Figure(marks=[line], axes=[xax, yax], animation_duration=1000, interaction=intsel)\n", "display(fig)" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "line.selected" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Handdraw" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "handdraw = bq.interacts.HandDraw(lines=line)\n", "fig.interaction = handdraw" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0.72310049, 0.74771262, 1.46769635, 0.36479014, 0.26309286,\n", " 0.28237225, 2.13196349, 1.91779684, 1.4187802 , 1.44013142,\n", " 0.52101798, 0.71377183, 0.34871661, -1.44261094, -1.50119749,\n", " -1.81874058, -3.45116389, -3.51829804, -2.02894208, -1.50763833,\n", " -0.89571114, -2.23720786, -1.76030949, -1.61185991, -1.08281467,\n", " -0.66018605, -2.01996678, -2.06136759, -2.81923845, -2.86932254,\n", " -3.76672347, -2.4542531 , -3.31322549, -4.21216765, -4.13758124,\n", " -5.21468031, -5.63934361, -6.46930821, -5.05813615, -4.27233232,\n", " -4.32980184, -4.72101889, -3.78010128, -3.3748972 , -2.87684479,\n", " -2.90303703, -4.59126706, -4.70373304, -5.23622296, -4.59116768,\n", " -3.57932525, -4.2372763 , -3.76889106, -2.03301206, -2.70072479,\n", " -1.01880305, -1.87138889, -1.84842914, -1.85957475, -1.84807585,\n", " -2.68575389, -3.27693699, -3.94465728, -3.61769469, -3.28765957,\n", " -1.06171524, 0.30927377, -0.20056947, 0.12430014, 1.12141812,\n", " 1.15201995, 1.08237837, 1.13395331, 2.00122994, 1.15290942,\n", " 0.82723995, 1.29767309, 1.60912016, 1.84870292, 1.47890176,\n", " 2.45143755, 4.58530579, 4.99172129, 4.79854459, 5.55428487,\n", " 5.01515224, 4.26546189, 4.29827064, 1.71547401, 0.56152364,\n", " 0.21356179, -1.13982707, -2.17247017, -2.60921851, -4.2521838 ,\n", " -4.6582556 , -5.19352576, -5.16812055, -4.01393652, -3.84143211])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "line.y[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Moving points around" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "2b442a6ed38443979345d6fe01eda274", "version_major": "2", "version_minor": "0" }, "text/plain": [ "A Jupyter Widget" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "from bqplot import *\n", "\n", "size = 100\n", "np.random.seed(0)\n", "x_data = range(size)\n", "y_data = np.cumsum(np.random.randn(size) * 100.0)\n", "\n", "## Enabling moving of points in scatter. Try to click and drag any of the points in the scatter and \n", "## notice the line representing the mean of the data update\n", "\n", "sc_x = LinearScale()\n", "sc_y = LinearScale()\n", "\n", "scat = Scatter(x=x_data[:10], y=y_data[:10], scales={'x': sc_x, 'y': sc_y}, default_colors=['blue'],\n", " enable_move=True)\n", "lin = Lines(scales={'x': sc_x, 'y': sc_y}, stroke_width=4, line_style='dashed', colors=['orange'])\n", "m = Label(value='Mean is %s'%np.mean(scat.y))\n", "\n", "def update_line(change):\n", " with lin.hold_sync():\n", " lin.x = [np.min(scat.x), np.max(scat.x)]\n", " lin.y = [np.mean(scat.y), np.mean(scat.y)]\n", " m.value='Mean is %s'%np.mean(scat.y)\n", " \n", "\n", "update_line(None)\n", "\n", "# update line on change of x or y of scatter\n", "scat.observe(update_line, names='x')\n", "scat.observe(update_line, names='y')\n", "\n", "ax_x = Axis(scale=sc_x)\n", "ax_y = Axis(scale=sc_y, tick_format='0.2f', orientation='vertical')\n", "\n", "fig = Figure(marks=[scat, lin], axes=[ax_x, ax_y])\n", "\n", "## In this case on drag, the line updates as you move the points.\n", "with scat.hold_sync():\n", " scat.enable_move = True\n", " scat.update_on_move = True\n", " scat.enable_add = False\n", "\n", "display(m, fig)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "widgets-tutorial", "language": "python", "name": "widgets-tutorial" }, "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.5" }, "widgets": { "state": { "0ba98b0561564e5987dba19d1b574c04": { "views": [ { "cell_index": 29 } ] }, "1ffa1ac6658e4eef89e45cf62daae339": { "views": [ { "cell_index": 30 } ] }, "42735872becb4c43b817ccff90973d63": { "views": [ { "cell_index": 15 } ] }, "4b9a5b18593545faba761a719b2e6039": { "views": [ { "cell_index": 17 } ] }, "7fb14b25d15240ec820c565619fe4f11": { "views": [ { "cell_index": 7 } ] }, "99604f1b70c54e19a508c95d705ce488": { "views": [ { "cell_index": 9 } ] }, "bf805af773d94496888afbe9e2bd3d37": { "views": [ { "cell_index": 13 } ] }, "dc1b84a0e5fa4ed5a42454cfc52c44f5": { "views": [ { "cell_index": 25 } ] }, "f30275bcf69e426c9d45a525833198d0": { "views": [ { "cell_index": 5 } ] } }, "version": "2.0.0-dev" } }, "nbformat": 4, "nbformat_minor": 2 }