Skip to content

Commit

Permalink
Only evaluate rx if it is an Reactive Expression (#6014)
Browse files Browse the repository at this point in the history
Co-authored-by: Philipp Rudiger <[email protected]>
  • Loading branch information
hoxbro and philippjfr authored Dec 20, 2023
1 parent b30ae90 commit 03eeb82
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 66 deletions.
12 changes: 5 additions & 7 deletions holoviews/core/spaces.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import itertools
import types
from collections import defaultdict
from contextlib import contextmanager, suppress
from contextlib import contextmanager
from functools import partial
from itertools import groupby
from numbers import Number
Expand Down Expand Up @@ -546,12 +546,10 @@ def __call__(self, *args, **kwargs):
# Nothing to do for callbacks that accept no arguments
kwarg_hash = kwargs.pop('_memoization_hash_', ())
(self.args, self.kwargs) = (args, kwargs)
if hasattr(self.callable, 'rx'):
with suppress(TypeError):
# If param.bind is used and not all arguments are set
# it will raise TypeError
return self.callable.rx.value
if not args and not kwargs and not any(kwarg_hash): return self.callable()
if util.param_version >= util.Version('2.0.0') and isinstance(self.callable, param.rx):
return self.callable.rx.value
elif not args and not kwargs and not any(kwarg_hash):
return self.callable()
inputs = [i for i in self.inputs if isinstance(i, DynamicMap)]
streams = []
for stream in [s for i in inputs for s in get_nested_streams(i)]:
Expand Down
19 changes: 19 additions & 0 deletions holoviews/tests/core/test_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from holoviews.streams import (
Buffer,
LinkedStream,
Params,
PointerX,
PointerXY,
PointerY,
Expand Down Expand Up @@ -846,6 +847,24 @@ def history_callback(x):
self.assertEqual(dmap[()], Curve([1, 1, 1, 2, 2, 2]))


class DynamicMapRX(ComparisonTestCase):

def test_dynamic_rx(self):
freq = param.rx(1)
rx_curve = param.rx(sine_array)(0, freq).rx.pipe(Curve)
dmap = DynamicMap(rx_curve)
assert len(dmap.streams) == 1
pstream = dmap.streams[0]
assert isinstance(pstream, Params)
assert len(pstream.parameters) == 2
fn_param, freq_param = pstream.parameters
assert getattr(fn_param.owner, fn_param.name) == sine_array
assert getattr(freq_param.owner, freq_param.name) == 1
self.assertEqual(dmap[()], Curve(sine_array(0, 1)))
freq.rx.value = 2
self.assertEqual(dmap[()], Curve(sine_array(0, 2)))


class StreamSubscribersAddandClear(ComparisonTestCase):

def setUp(self):
Expand Down
88 changes: 58 additions & 30 deletions holoviews/tests/ui/bokeh/test_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,26 @@

pytestmark = pytest.mark.ui

from panel.io.server import serve
import panel as pn
from panel.pane.holoviews import HoloViews
from panel.tests.util import wait_until
from panel.tests.util import serve_and_wait, wait_until

from holoviews import Curve, Scatter
from holoviews.plotting.bokeh import BokehRenderer
import holoviews as hv
from holoviews import Curve, DynamicMap, Scatter
from holoviews.streams import BoundsXY, Lasso, RangeXY


@pytest.mark.usefixtures("bokeh_backend")
def test_box_select(page, port):
hv_scatter = Scatter([1, 2, 3]).opts(
backend='bokeh', tools=['box_select'], active_tools=['box_select']
tools=['box_select'], active_tools=['box_select']
)

bounds = BoundsXY(source=hv_scatter)

pn_scatter = HoloViews(hv_scatter, renderer=BokehRenderer)

serve(pn_scatter, port=port, threaded=True, show=False)

time.sleep(0.5)
pn_scatter = HoloViews(hv_scatter)

serve_and_wait(pn_scatter, port=port)
page.goto(f"http://localhost:{port}")

hv_plot = page.locator('.bk-events')
Expand All @@ -50,20 +48,17 @@ def test_box_select(page, port):
wait_until(lambda: bounds.bounds == expected_bounds, page)



@pytest.mark.usefixtures("bokeh_backend")
def test_lasso_select(page, port):
hv_scatter = Scatter([1, 2, 3]).opts(
backend='bokeh', tools=['lasso_select'], active_tools=['lasso_select']
tools=['lasso_select'], active_tools=['lasso_select']
)

lasso = Lasso(source=hv_scatter)

pn_scatter = HoloViews(hv_scatter, renderer=BokehRenderer)

serve(pn_scatter, port=port, threaded=True, show=False)

time.sleep(0.5)
pn_scatter = HoloViews(hv_scatter)

serve_and_wait(pn_scatter, port=port)
page.goto(f"http://localhost:{port}")

hv_plot = page.locator('.bk-events')
Expand Down Expand Up @@ -96,18 +91,15 @@ def test_lasso_select(page, port):
])
np.testing.assert_almost_equal(lasso.geometry, expected_array)


@pytest.mark.usefixtures("bokeh_backend")
def test_rangexy(page, port):
hv_scatter = Scatter([1, 2, 3]).opts(backend='bokeh', active_tools=['box_zoom'])
hv_scatter = Scatter([1, 2, 3]).opts(active_tools=['box_zoom'])

rangexy = RangeXY(source=hv_scatter)

pn_scatter = HoloViews(hv_scatter, renderer=BokehRenderer)

serve(pn_scatter, port=port, threaded=True, show=False)

time.sleep(0.5)
pn_scatter = HoloViews(hv_scatter)

serve_and_wait(pn_scatter, port=port)
page.goto(f"http://localhost:{port}")

hv_plot = page.locator('.bk-events')
Expand All @@ -126,20 +118,18 @@ def test_rangexy(page, port):
expected_yrange = (1.8285714285714285, 2.3183673469387758)
wait_until(lambda: rangexy.x_range == expected_xrange and rangexy.y_range == expected_yrange, page)

@pytest.mark.usefixtures("bokeh_backend")
def test_multi_axis_rangexy(page, port):
c1 = Curve(np.arange(100).cumsum(), vdims='y')
c2 = Curve(-np.arange(100).cumsum(), vdims='y2')
s1 = RangeXY(source=c1)
s2 = RangeXY(source=c2)

overlay = (c1 * c2).opts(backend='bokeh', multi_y=True)
overlay = (c1 * c2).opts(multi_y=True)

pn_scatter = HoloViews(overlay, renderer=BokehRenderer)

serve(pn_scatter, port=port, threaded=True, show=False)

time.sleep(0.5)
pn_scatter = HoloViews(overlay)

serve_and_wait(pn_scatter, port=port)
page.goto(f"http://localhost:{port}")

hv_plot = page.locator('.bk-events')
Expand All @@ -162,3 +152,41 @@ def test_multi_axis_rangexy(page, port):
s1.y_range == expected_yrange1 and
s2.y_range == expected_yrange2
), page)


@pytest.mark.usefixtures("bokeh_backend")
def test_bind_trigger(page, port):
# Regression test for https://github.com/holoviz/holoviews/issues/6013

BOUND_COUNT, RANGE_COUNT = [0], [0]

def bound_function():
BOUND_COUNT[0] += 1
return Curve([])


def range_function(x_range, y_range):
RANGE_COUNT[0] += 1
return Curve([])

range_dmap = DynamicMap(range_function, streams=[hv.streams.RangeXY()])
bind_dmap = DynamicMap(pn.bind(bound_function))
widget = pn.pane.HoloViews(bind_dmap * range_dmap)

serve_and_wait(widget, port=port)
page.goto(f"http://localhost:{port}")

hv_plot = page.locator('.bk-events')
expect(hv_plot).to_have_count(1)

bbox = hv_plot.bounding_box()
hv_plot.click()

page.mouse.move(bbox['x']+100, bbox['y']+100)
page.mouse.down()
page.mouse.move(bbox['x']+150, bbox['y']+150, steps=5)
page.mouse.up()

wait_until(lambda: RANGE_COUNT[0] > 2, page)

assert BOUND_COUNT[0] == 1
29 changes: 0 additions & 29 deletions holoviews/tests/ui/bokeh/test_layout.py

This file was deleted.

0 comments on commit 03eeb82

Please sign in to comment.