{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Overview\n", "\n", "This notebook introduces the ipyplotly enhancements to the plotly.py visualization library and demonstrates some of its features.\n", "\n", "\n", "## New Features\n", "\n", " - Traces can be added and updated interactively by simply assigning to properties\n", " - The full Traces and Layout API is generated from the plotly schema to provide a great experience for interactive use in the notebook\n", " - Data validation covering the full API with clear, informative error messages\n", " - Jupyter friendly docstrings on constructor params and properties\n", " - Support for setting array properties as numpy arrays. When numpy arrays are used, ipywidgets binary serialization protocol is used to avoid converting these to JSON strings.\n", " - Context manager API for animation\n", " - Programmatic export of figures to static SVG images (and PNG and PDF with cairosvg installed)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Imports" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# ipyplotly\n", "from plotly.graph_objs import FigureWidget\n", "from plotly.callbacks import Points, InputDeviceState\n", "\n", "# pandas\n", "import pandas as pd\n", "\n", "# numpy\n", "import numpy as np\n", "\n", "# scikit learn\n", "from sklearn import datasets\n", "\n", "# ipywidgets\n", "from ipywidgets import HBox, VBox, Button\n", "\n", "# functools\n", "from functools import partial" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | sepal_length | \n", "sepal_width | \n", "petal_length | \n", "petal_width | \n", "
|---|---|---|---|---|
| 0 | \n", "5.1 | \n", "3.5 | \n", "1.4 | \n", "0.2 | \n", "
| 1 | \n", "4.9 | \n", "3.0 | \n", "1.4 | \n", "0.2 | \n", "
| 2 | \n", "4.7 | \n", "3.2 | \n", "1.3 | \n", "0.2 | \n", "
| 3 | \n", "4.6 | \n", "3.1 | \n", "1.5 | \n", "0.2 | \n", "
| 4 | \n", "5.0 | \n", "3.6 | \n", "1.4 | \n", "0.2 | \n", "
Failed to display Jupyter Widget of type FigureWidget.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "FigureWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f1" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "scatt1.mode?" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# That's not what we wanted, change the mode to 'markers'\n", "scatt1.mode = 'markers'" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Set size to 8\n", "scatt1.marker.size = 8" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Color markers by iris class\n", "scatt1.marker.color = iris_class" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Change colorscale\n", "scatt1.marker.cmin = 0.5\n", "scatt1.marker.cmax = 3.5\n", "scatt1.marker.colorscale = [[0, 'red'], [0.33, 'red'], \n", " [0.33, 'green'], [0.67, 'green'], \n", " [0.67, 'blue'], [1.0, 'blue']]\n", "\n", "scatt1.marker.showscale = True" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Fix up colorscale ticks\n", "scatt1.marker.colorbar.ticks = 'outside'\n", "scatt1.marker.colorbar.tickvals = [1, 2, 3]\n", "scatt1.marker.colorbar.ticktext = iris_data.target_names.tolist()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Set colorscale title\n", "scatt1.marker.colorbar.title = 'Species'\n", "scatt1.marker.colorbar.titlefont.size = 16\n", "scatt1.marker.colorbar.titlefont.family = 'Rockwell'" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Add axis labels\n", "f1.layout.xaxis.title = 'sepal_length'\n", "f1.layout.yaxis.title = 'petal_width'" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1d5079ee9c1542cfa4ecc1f8e93abd1f", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type FigureWidget.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "FigureWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f1" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Hover info\n", "scatt1.text = iris_data.target_names[iris_data.target]\n", "scatt1.hoverinfo = 'text+x+y'\n", "f1.layout.hovermode = 'closest'" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1d5079ee9c1542cfa4ecc1f8e93abd1f", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type FigureWidget.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "FigureWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Animate marker size change" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Set marker size based on petal_length\n", "with f1.batch_animate(duration=1000):\n", " scatt1.marker.size = np.sqrt(iris_df.petal_length.values * 50)\n", " " ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Restore constant marker size\n", "with f1.batch_animate(duration=1000):\n", " scatt1.marker.size = 8" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set drag mode property callback\n", "Make points more transparent when `dragmode` is `zoom`" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def set_opacity(marker, layout, dragmode):\n", " if dragmode == 'zoom':\n", " marker.opacity = 0.5\n", " else:\n", " marker.opacity = 1.0" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f1.layout.on_change(partial(set_opacity, scatt1.marker), 'dragmode')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Configure colorscale for brushing" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true }, "outputs": [], "source": [ "scatt1.marker.colorbar = None\n", "scatt1.marker.colorscale = [[0, 'lightgray'], [0.5, 'lightgray'], [0.5, 'red'], [1, 'red']]\n", "scatt1.marker.cmin = -0.5\n", "scatt1.marker.cmax = 1.5\n", "scatt1.marker.colorbar.ticks = 'outside'\n", "scatt1.marker.colorbar.tickvals = [0, 1]\n", "scatt1.marker.colorbar.ticktext = ['unselected', 'selected']" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Reset colors to zeros (unselected)\n", "scatt1.marker.color = np.zeros(iris_class.size)\n", "selected = np.zeros(iris_class.size)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1d5079ee9c1542cfa4ecc1f8e93abd1f", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type FigureWidget.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "FigureWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Configure brushing callback" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Assigning these variables here is not required. But doing so tricks Jupyter into \n", "# providing property tab completion on the parameters to the brush function below\n", "trace, points, state = scatt1, Points(), InputDeviceState()" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def brush(trace, points, state):\n", " inds = np.array(points.point_inds)\n", " if inds.size:\n", " selected[inds] = 1\n", " trace.marker.color = selected" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true }, "outputs": [], "source": [ "scatt1.on_selected(brush)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now box or lasso select points on the figure and see them turn red" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Reset brush\n", "selected = np.zeros(iris_class.size)\n", "scatt1.marker.color = selected" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create second plot with different features" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "scrolled": false }, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e88d348677544c1ea2eca95ea8b30fdd", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type FigureWidget.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "FigureWidget()" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "f2 = FigureWidget(data=[{'type': 'scatter',\n", " 'x': iris_df.petal_length, \n", " 'y': iris_df.sepal_width,\n", " 'mode': 'markers'}])\n", "f2" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Set axis titles\n", "f2.layout.xaxis.title = 'petal_length'\n", "f2.layout.yaxis.title = 'sepal_width'" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Grab trace reference\n", "scatt2 = f2.data[0]" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": true, "scrolled": false }, "outputs": [], "source": [ "# Set marker styles / colorbars to match between figures\n", "scatt2.marker = scatt1.marker" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Configure brush on both plots to update both plots\n", "def brush(trace, points, state):\n", " inds = np.array(points.point_inds)\n", " if inds.size:\n", " selected = scatt1.marker.color.copy()\n", " selected[inds] = 1\n", " scatt1.marker.color = selected\n", " scatt2.marker.color = selected \n", " \n", "scatt1.on_selected(brush)\n", "scatt2.on_selected(brush)" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f2.layout.on_change(partial(set_opacity, scatt2.marker), 'dragmode')" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Reset brush\n", "def reset_brush(btn):\n", " selected = np.zeros(iris_class.size)\n", " scatt1.marker.color = selected\n", " scatt2.marker.color = selected" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Create reset button\n", "button = Button(description=\"clear\")\n", "button.on_click(reset_brush)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Hide colorbar for figure 1\n", "scatt1.marker.showscale = False" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Set dragmode to lasso for both plots\n", "f1.layout.dragmode = 'lasso'\n", "f2.layout.dragmode = 'lasso'" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Display two figures and the reset button\n", "f1.layout.width = 500\n", "f2.layout.width = 500" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "74f7b16952584919b650fbc442c21773", "version_major": 2, "version_minor": 0 }, "text/html": [ "Failed to display Jupyter Widget of type VBox.
\n", " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", " that the widgets JavaScript is still loading. If this message persists, it\n", " likely means that the widgets JavaScript library is either not installed or\n", " not enabled. See the Jupyter\n", " Widgets Documentation for setup instructions.\n", "
\n", "\n", " If you're reading this message in another frontend (for example, a static\n", " rendering on GitHub or NBViewer),\n", " it may mean that your frontend doesn't currently support widgets.\n", "
\n" ], "text/plain": [ "VBox(children=(HBox(children=(FigureWidget(), FigureWidget())), Button(description='clear', style=ButtonStyle())))" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "VBox([HBox([f1, f2]), button])" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Save figure 2 to a svg image in the exports directory\n", "f2.save_image('exports/f2.svg')" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Save figure 1 to a pdf in the exports directory (requires cairosvg be installed)\n", "# f1.save_image('exports/f1.pdf')" ] } ], "metadata": { "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.12" } }, "nbformat": 4, "nbformat_minor": 2 }