Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BoundsX/BoundsY streams #1554

Merged
merged 3 commits into from Jun 16, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
85 changes: 85 additions & 0 deletions examples/streams/bokeh/boundsx_selection.ipynb
@@ -0,0 +1,85 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
" <dl class=\"dl-horizontal\">\n",
" <dt>Title</dt> <dd> XBounds stream example</dd>\n",
" <dt>Description</dt> <dd>A linked streams example demonstrating how to use XBounds streams.</dd>\n",
" <dt>Backends</dt> <dd> Bokeh</dd>\n",
" <dt>Tags</dt> <dd> streams, linked, interactive</dd>\n",
" </dl>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"from holoviews import streams\n",
"hv.notebook_extension('bokeh')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%opts Curve[tools=['xbox_select']]\n",
"\n",
"n=200\n",
"xs = np.linspace(0, 1, n)\n",
"ys = np.cumsum(np.random.randn(n))\n",
"df = pd.DataFrame({'x': xs, 'y': ys})\n",
"curve = hv.Curve(df)\n",
"\n",
"def make_from_boundsx(boundsx):\n",
" sub = df.set_index('x').loc[boundsx[0]:boundsx[1]]\n",
" return hv.Table(sub.describe().reset_index().values, kdims=['stat'], vdims=['value'])\n",
"\n",
"curve + hv.DynamicMap(make_from_boundsx, streams=[streams.BoundsX(source=curve, boundsx=(0,0))])"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"<center><img src=\"http://assets.holoviews.org/gifs/examples/streams/bokeh/boundsx_selection.gif\"></center>"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"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.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
84 changes: 84 additions & 0 deletions examples/streams/bokeh/boundsy_selection.ipynb
@@ -0,0 +1,84 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
" <dl class=\"dl-horizontal\">\n",
" <dt>Title</dt> <dd> YBounds stream example</dd>\n",
" <dt>Description</dt> <dd>A linked streams example demonstrating how to use YBounds streams.</dd>\n",
" <dt>Backends</dt> <dd> Bokeh</dd>\n",
" <dt>Tags</dt> <dd> streams, linked, interactive</dd>\n",
" </dl>\n",
"</div>"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import holoviews as hv\n",
"from holoviews import streams\n",
"hv.notebook_extension('bokeh')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%opts Curve[tools=['ybox_select']]\n",
"\n",
"xs = np.linspace(0, 1, 200)\n",
"ys = xs*(1-xs)\n",
"curve = hv.Curve((xs,ys))\n",
"\n",
"bounds_stream = streams.BoundsY(source=curve,boundsy=(0,0))\n",
"\n",
"def make_area(boundsy):\n",
" return hv.Area((xs, np.minimum(ys, boundsy[0]), np.minimum(ys, boundsy[1])), vdims=['min','max'])\n",
"\n",
"\n",
"def make_items(boundsy):\n",
" times = [\"{0:.2f}\".format(x) for x in sorted(np.roots([-1,1,-boundsy[0]])) + sorted(np.roots([-1,1,-boundsy[1]]))]\n",
" return hv.ItemTable(sorted(zip(['1_entry', '2_exit', '1_exit', '2_entry'], times)))\n",
"\n",
"\n",
"curve * hv.DynamicMap(make_area, streams=[bounds_stream]) + hv.DynamicMap(make_items, streams=[bounds_stream])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<center><img src=\"http://assets.holoviews.org/gifs/examples/streams/bokeh/boundsy_selection.gif\"></center>"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"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.5.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
39 changes: 35 additions & 4 deletions holoviews/plotting/bokeh/callbacks.py
Expand Up @@ -3,8 +3,9 @@

from ...core import OrderedDict
from ...streams import (Stream, PointerXY, RangeXY, Selection1D, RangeX,
RangeY, PointerX, PointerY, Bounds, Tap, SingleTap,
DoubleTap, MouseEnter, MouseLeave, PlotSize, Draw)
RangeY, PointerX, PointerY, Bounds, BoundsX, BoundsY,
Tap, SingleTap, DoubleTap, MouseEnter, MouseLeave,
PlotSize, Draw)
from ...streams import PositionX, PositionY, PositionXY # Deprecated: remove in 2.0
from ..comms import JupyterCommJS
from .util import bokeh_version
Expand Down Expand Up @@ -687,12 +688,10 @@ def _process_msg(self, msg):
return {}



class BoundsCallback(Callback):
"""
Returns the bounds of a box_select tool.
"""

attributes = {'x0': 'cb_data.geometry.x0',
'x1': 'cb_data.geometry.x1',
'y0': 'cb_data.geometry.y0',
Expand All @@ -706,6 +705,36 @@ def _process_msg(self, msg):
return {}


class BoundsXCallback(Callback):
"""
Returns the bounds of a xbox_select tool.
"""

attributes = {'x0': 'cb_data.geometry.x0', 'x1': 'cb_data.geometry.x1'}
models = ['xbox_select']

def _process_msg(self, msg):
if all(c in msg for c in ['x0', 'x1']):
return {'boundsx': (msg['x0'], msg['x1'])}
else:
return {}


class BoundsYCallback(Callback):
"""
Returns the bounds of a ybox_select tool.
"""

attributes = {'y0': 'cb_data.geometry.y0', 'y1': 'cb_data.geometry.y1'}
models = ['ybox_select']

def _process_msg(self, msg):
if all(c in msg for c in ['y0', 'y1']):
return {'boundsy': (msg['y0'], msg['y1'])}
else:
return {}


class Selection1DCallback(Callback):
"""
Returns the current selection on a ColumnDataSource.
Expand Down Expand Up @@ -736,6 +765,8 @@ def _process_msg(self, msg):
callbacks[RangeX] = RangeXCallback
callbacks[RangeY] = RangeYCallback
callbacks[Bounds] = BoundsCallback
callbacks[BoundsX] = BoundsXCallback
callbacks[BoundsY] = BoundsYCallback
callbacks[Selection1D] = Selection1DCallback
callbacks[PlotSize] = PlotSizeCallback
callbacks[Draw] = DrawCallback
Expand Down
24 changes: 23 additions & 1 deletion holoviews/streams.py
Expand Up @@ -509,7 +509,29 @@ class Bounds(LinkedStream):

bounds = param.NumericTuple(default=None, constant=True, length=4,
allow_None=True, doc="""
Bounds defined as (left, bottom, top, right) tuple.""")
Bounds defined as (left, bottom, right, top) tuple.""")


class BoundsX(LinkedStream):
"""
A stream representing the bounds of a box selection as an
tuple of the left and right coordinates.
"""

boundsx = param.NumericTuple(default=None, constant=True, length=2,
allow_None=True, doc="""
Bounds defined as (left, right) tuple.""")


class BoundsY(LinkedStream):
"""
A stream representing the bounds of a box selection as an
tuple of the bottom and top coordinates.
"""

boundsy = param.NumericTuple(default=None, constant=True, length=2,
allow_None=True, doc="""
Bounds defined as (bottom, top) tuple.""")


class Selection1D(LinkedStream):
Expand Down