Skip to content

Commit

Permalink
Merge 44262c0 into fee1696
Browse files Browse the repository at this point in the history
  • Loading branch information
philippjfr committed Dec 14, 2018
2 parents fee1696 + 44262c0 commit 50a2200
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 19 deletions.
104 changes: 86 additions & 18 deletions examples/user_guide/11-Responding_to_Events.ipynb
Expand Up @@ -15,6 +15,8 @@
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"from holoviews import opts\n",
"\n",
"hv.extension('bokeh')"
]
},
Expand All @@ -37,11 +39,16 @@
"outputs": [],
"source": [
"# Styles and plot options used in this user guide\n",
"%opts Ellipse [bgcolor='white'] (color='black')\n",
"%opts Image (cmap='viridis')\n",
"%opts VLine HLine (color='red' line_width=2)\n",
"%opts Path [show_grid=False bgcolor='white'] (color='black' line_dash='dashdot')\n",
"%opts Area (fill_color='cornsilk' line_width=2 line_color='black')"
"\n",
"opts.defaults(\n",
" opts.Area(fill_color='cornsilk', line_width=2,\n",
" line_color='black'),\n",
" opts.Ellipse(bgcolor='white', color='black'),\n",
" opts.HLine(color='red', line_width=2),\n",
" opts.Image(cmap='viridis'),\n",
" opts.Path(bgcolor='white', color='black', line_dash='dashdot',\n",
" padding=0.1, show_grid=False),\n",
" opts.VLine(color='red', line_width=2))"
]
},
{
Expand All @@ -55,7 +62,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Before introducing streams, let us declare a simple ``DynamicMap`` of the sort discussed in the [Live Data](06-Live_Data.ipynb) user guide. This example consists of a ``Curve`` element showing a [Lissajous curve](https://en.wikipedia.org/wiki/Lissajous_curve) with ``VLine`` and ``HLine`` annotations to form a crosshair:"
"Before introducing streams, let us declare a simple ``DynamicMap`` of the sort discussed in the [Live Data](06-Live_Data.ipynb) user guide. This example consists of a ``Path`` element showing a [Lissajous curve](https://en.wikipedia.org/wiki/Lissajous_curve) with dynamic ``VLine`` and ``HLine`` annotations to form a crosshair:"
]
},
{
Expand All @@ -66,14 +73,18 @@
"source": [
"lin = np.linspace(-np.pi,np.pi,300)\n",
"\n",
"def lissajous(t, a,b, delta):\n",
"def lissajous(t, a=3, b=5, delta=np.pi/2.):\n",
" return (np.sin(a * t + delta), np.sin(b * t))\n",
"\n",
"def lissajous_curve(t, a=3,b=5, delta=np.pi/2):\n",
"def lissajous_crosshair(t, a=3, b=5, delta=np.pi/2):\n",
" (x,y) = lissajous(t,a,b,delta)\n",
" return hv.Path(lissajous(lin,a,b,delta)) * hv.VLine(x) * hv.HLine(y)\n",
" return hv.VLine(x) * hv.HLine(y)\n",
"\n",
"crosshair = hv.DynamicMap(lissajous_crosshair, kdims='t').redim.range(t=(-3.,3.))\n",
"\n",
"hv.DynamicMap(lissajous_curve, kdims='t').redim.range(t=(-3.,3.))"
"path = hv.Path(lissajous(lin))\n",
"\n",
"path * crosshair"
]
},
{
Expand All @@ -95,7 +106,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The core concept behind a stream is simple: it is a parameter that can change over time that automatically refreshes code depending on those parameter values. \n",
"The core concept behind a stream is simple: it defines one or more parameters that can change over time that automatically refreshes code depending on those parameter values. \n",
"\n",
"Like all objects in HoloViews, these parameters are declared using [param](https://ioam.github.io/param) and streams are defined as a parameterized subclass of the ``holoviews.streams.Stream``. A more convenient way is to use the ``Stream.define`` classmethod:"
]
Expand Down Expand Up @@ -195,7 +206,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now supply this streams object to a ``DynamicMap`` using the same ``lissajous_curve`` callback above by adding it to the ``streams`` list:"
"We can now supply this streams object to a ``DynamicMap`` using the same ``lissajous_crosshair`` callback from above by adding it to the ``streams`` list:"
]
},
{
Expand All @@ -204,8 +215,8 @@
"metadata": {},
"outputs": [],
"source": [
"dmap = hv.DynamicMap(lissajous_curve, streams=[time])\n",
"dmap + lissajous_curve(t=np.pi/4)"
"dmap = hv.DynamicMap(lissajous_crosshair, streams=[time])\n",
"path * dmap + path * lissajous_crosshair(t=np.pi/4.)"
]
},
{
Expand All @@ -223,7 +234,7 @@
"metadata": {},
"outputs": [],
"source": [
"dmap.event( t=0.2)"
"dmap.event(t=0.2)"
]
},
{
Expand Down Expand Up @@ -279,10 +290,13 @@
"XY = Stream.define('XY',x=0.0,y=0.0)\n",
"\n",
"def marker(x,y):\n",
" return hv.Image(np.sin(xx)*np.cos(yy)) * hv.VLine(x) * hv.HLine(y)\n",
" return hv.VLine(x) * hv.HLine(y)\n",
"\n",
"image = hv.Image(np.sin(xx)*np.cos(yy))\n",
"\n",
"dmap = hv.DynamicMap(marker, streams=[XY()])\n",
"dmap"
"\n",
"image * dmap"
]
},
{
Expand Down Expand Up @@ -310,12 +324,66 @@
"```python\n",
"X = Stream.define('X',x=0.0)\n",
"Y = Stream.define('Y',y=0.0)\n",
"hv.DynamicMap(marker, streams=[X(),Y()])\n",
"hv.DynamicMap(marker, streams=[X(), Y()])\n",
"```\n",
"\n",
"The reason why you might want to list multiple streams instead of always defining a single stream containing all the required stream parameters will be made clear in the [Custom Interactivity](./12-Custom_Interactivity.ipynb) guide."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Using Parameterized classes as a stream\n",
"\n",
"Creating a custom ``Stream`` class is one easy way to declare parameters, however in many cases you may have already expressed your domain knowledge on a ``Parameterized`` class. A ``DynamicMap`` can easily be linked to the parameters of the class using a so called ``Params`` stream, let's define a simple example which will let use dynamically alter the style applied to the ``Image`` from the previous example. We define a ``Style`` class with two parameters, one to control the colormap and another to vary the number of color levels:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from holoviews.streams import Params\n",
"\n",
"class Style(param.Parameterized):\n",
"\n",
" cmap = param.ObjectSelector(default='viridis', objects=['viridis', 'plasma', 'magma'])\n",
"\n",
" color_levels = param.Integer(default=255, bounds=(1, 255))\n",
"\n",
"style = Style()\n",
"\n",
"stream = Params(style)\n",
"\n",
"hv.DynamicMap(image.opts, streams=[stream]).opts(colorbar=True, width=400)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Instead of providing a custom callback function we supplied the ``image.opts`` method, which applies the parameters directly as options. Unlike a regular streams class the plot will update whenever a parameter on the instance or class changes, e.g. we can update set the ``cmap`` and ``color_level`` parameters and watch the plot update in response:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"style.color_levels = 10\n",
"style.cmap = 'plasma'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is a powerful pattern to link parameters to a plot, particularly when combined with the [Panel](http://panel.pyviz.org/) library, which makes it easy to generate a set of widgets from a Parameterized class. To see how this works in practice see the [Dashboards user guide](./16-Dashboards.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {},
Expand Down
16 changes: 15 additions & 1 deletion holoviews/tests/core/testdynamic.py
@@ -1,7 +1,8 @@
import uuid
from collections import deque
import time
from collections import deque

import param
import numpy as np
from holoviews import Dimension, NdLayout, GridSpace, Layout, NdOverlay
from holoviews.core.spaces import DynamicMap, HoloMap, Callable
Expand Down Expand Up @@ -398,6 +399,19 @@ def test_dynamic_util_inherits_dim_streams(self):
hist = Dynamic(self.dmap)
self.assertEqual(hist.streams, self.dmap.streams[1:])

def test_dynamic_util_parameterized_method(self):
class Test(param.Parameterized):
label = param.String(default='test')

@param.depends('label')
def apply_label(self, obj):
return obj.relabel(self.label)

test = Test()
dmap = Dynamic(self.dmap, operation=test.apply_label)
test.label = 'custom label'
self.assertEqual(dmap[(0, 3)].label, 'custom label')

def test_dynamic_util_inherits_dim_streams_clash(self):
exception = ("The supplied stream objects PointerX\(x=None\) and "
"PointerX\(x=0\) clash on the following parameters: \['x'\]")
Expand Down

0 comments on commit 50a2200

Please sign in to comment.