Skip to content

Commit

Permalink
Add ability to define Links between plots (#2832)
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Jul 3, 2018
1 parent a14c621 commit 3cb7c83
Show file tree
Hide file tree
Showing 12 changed files with 885 additions and 7 deletions.
3 changes: 3 additions & 0 deletions doc/user_guide/index.rst
Expand Up @@ -87,6 +87,9 @@ These guides provide detail about specific additional features in HoloViews:
* `Deploying Bokeh Apps <Deploying_Bokeh_Apps.html>`_
Using `bokeh server <http://bokeh.pydata.org/en/latest/docs/user_guide/server.html>`_ using scripts and notebooks.

* `Link bokeh plots <Linking_Plots.html>`_
Using Links to define custom interactions on a plot without a Python server

* `Plotting with matplotlib <Plotting_with_Matplotlib.html>`_
Styling options and unique Matplotlib features such as GIF/MP4 support.

Expand Down
87 changes: 87 additions & 0 deletions examples/gallery/demos/bokeh/choropleth_data_link.ipynb
@@ -0,0 +1,87 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import holoviews as hv\n",
"\n",
"from holoviews.plotting.links import DataLink\n",
"\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This example demonstrates how to use a DataLink to join two elements displaying the same data, a choropleth of the Texas unemployment rate alongside a Table of the same data. By linking the two selecting a polygon will highlight it in the table and vice versa."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.sampledata.us_counties import data as counties\n",
"from bokeh.sampledata.unemployment import data as unemployment\n",
"\n",
"counties = [dict(county, Unemployment=unemployment[cid])\n",
" for cid, county in counties.items()\n",
" if county[\"state\"] == \"tx\"]\n",
"\n",
"county_data = [(county['detailed name'], county['Unemployment']) for county in counties]\n",
"\n",
"choropleth = hv.Polygons(counties, ['lons', 'lats'], [('detailed name', 'County'), 'Unemployment'], label='Texas Unemployment')\n",
"table = hv.Table(county_data, [('detailed name', 'County'), 'Unemployment'])\n",
"\n",
"print(len(choropleth.data), len(table))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare Plot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As shown above the two elements have the same length meaning that they can be linked. Linking the data in this way allows cross-selecting, e.g. by selecting one or more rows in the ``Table`` we can see the polygon for the county highlight in the choropleth:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"choropleth.options(width=500, height=500, tools=['hover', 'tap'], xaxis=None, yaxis=None, color_index='Unemployment', clone=False)\n",
"table.options(height=428, clone=False)\n",
"\n",
"# Link the choropleth and the table\n",
"DataLink(choropleth, table)\n",
"\n",
"choropleth + table"
]
}
],
"metadata": {
},
"nbformat": 4,
"nbformat_minor": 2
}
99 changes: 99 additions & 0 deletions examples/gallery/demos/bokeh/image_range_tool.ipynb
@@ -0,0 +1,99 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from itertools import islice\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import holoviews as hv\n",
"from holoviews.plotting.links import RangeToolLink\n",
"\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This demo demonstrates how to link two plots using the RangeToolLink along both axes. This can be useful to get an overview and a detailed view of some data at the same time."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def mandelbrot_generator(h,w, maxit, bounds):\n",
" \"Generator that yields the mandlebrot set.\"\n",
" (l,b,r,t) = bounds\n",
" y,x = np.ogrid[b:t : h*1j, l:r:w*1j]\n",
" c = x+y*1j\n",
" z = c\n",
" divtime = maxit + np.zeros(z.shape, dtype=int)\n",
" for i in range(maxit):\n",
" z = z**2 + c\n",
" diverge = z*np.conj(z) > 2**2\n",
" div_now = diverge & (divtime==maxit)\n",
" divtime[div_now] = i\n",
" z[diverge] = 2\n",
" yield divtime\n",
"\n",
"def mandelbrot(h,w, n, maxit, bounds):\n",
" \"Returns the mandelbrot set computed to maxit\"\n",
" iterable = mandelbrot_generator(h,w, maxit, bounds)\n",
" return next(islice(iterable, n, None))\n",
"\n",
"bounds = (-2,-1.4,0.8,1.4)\n",
"mbset = mandelbrot(800,800, 45, 46, bounds)\n",
"\n",
"mbset_image = hv.Image(mbset, bounds=bounds)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare plot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Having declared an ``Image`` of the Mandelbrot set we make a smaller and larger version of it. The smaller ``source`` will serve as an overview containing the ``RangeTool`` which allows selecting the region to show in the larger ``target`` plot. We can control which axes should be linked to the ``RangeTool`` with the axes parameter on the ``RangeToolLink``:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"src = mbset_image.options(width=300, height=300)\n",
"tgt = mbset_image.options(width=500, height=500, xaxis=None, yaxis=None)\n",
"\n",
"# Declare a RangeToolLink between the x- and y-axes of the two plots\n",
"RangeToolLink(src, tgt, axes=['x', 'y'])\n",
"\n",
"(tgt + src).options(shared_axes=False, clone=False)"
]
}
],
"metadata": {
},
"nbformat": 4,
"nbformat_minor": 2
}
79 changes: 79 additions & 0 deletions examples/gallery/demos/bokeh/timeseries_range_tool.ipynb
@@ -0,0 +1,79 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import holoviews as hv\n",
"\n",
"from holoviews.plotting.links import RangeToolLink\n",
"\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This demo demonstrates how to link two timeseries plots using the ``RangeToolLink`` along the x-axis. This can be useful to get an overview and a detailed view of some data at the same time."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare data"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.sampledata.stocks import AAPL\n",
"\n",
"aapl_df = pd.DataFrame(AAPL['close'], columns=['close'], index=pd.to_datetime(AAPL['date']))\n",
"aapl_df.index.name = 'Date'\n",
"\n",
"aapl_curve = hv.Curve(aapl_df, 'Date', ('close', 'Price ($)'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Declare plot"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Having declared a ``Curve`` element containing the AAPL stock closing prices we create two copies of it with different styling. One smaller view which will become the ``source`` of the link which will display the range tool, and a larger ``target`` view whose axes will be linked to the range of the ``RangeTool`` on the ``source``:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"tgt = aapl_curve.options(width=800, labelled=['y']).relabel('AAPL close price')\n",
"src = aapl_curve.options(width=800, height=100, yaxis=None)\n",
"\n",
"RangeToolLink(src, tgt)\n",
"\n",
"(tgt + src).options(shared_axes=False, clone=False).cols(1)"
]
}
],
"metadata": {
},
"nbformat": 4,
"nbformat_minor": 2
}

0 comments on commit 3cb7c83

Please sign in to comment.