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

holoviews Selection1D Tap: regression on panel 1.4 #6872

Closed
pmav99 opened this issue May 29, 2024 · 3 comments
Closed

holoviews Selection1D Tap: regression on panel 1.4 #6872

pmav99 opened this issue May 29, 2024 · 3 comments
Labels
bokeh Request is for change in bokeh

Comments

@pmav99
Copy link
Contributor

pmav99 commented May 29, 2024

I am not sure if this belongs here or on the holoviews bug-tracker.

I suspect that the issue is actually related to bokeh 3.3 vs 3.4 but holoviews doesn't restrict the bokeh version, while bokeh and panel releases seem to be coupled. This is why I am opening the ticket here. Feel free to move it if this is not the case.

Description of expected behavior and the observed behavior

After upgrading to panel 1.4 the Holoviews Selection1D Tap example (and possibly others) no longer works.

Up to panel 1.3, when you click on a new point, the previous point gets deselected and the regression plot on the right gets updated. On panel 1.4 the previous point remains selected and the regression plot keeps on showing the first point (i.e there is no update). If you deselect the first point, then only the second point remains selected and the regression plot gets updated.

ALL software version info

This has been tested on 2 different linux machines and a Mac. It's the same behavior everywhere.

anyio==4.4.0
argon2-cffi==23.1.0
argon2-cffi-bindings==21.2.0
arrow==1.3.0
asttokens==2.4.1
async-lru==2.0.4
attrs==23.2.0
Babel==2.15.0
beautifulsoup4==4.12.3
bleach==6.1.0
bokeh==3.4.1
certifi==2024.2.2
cffi==1.16.0
charset-normalizer==3.3.2
colorcet==3.1.0
comm==0.2.2
contourpy==1.2.1
debugpy==1.8.1
decorator==5.1.1
defusedxml==0.7.1
executing==2.0.1
fastjsonschema==2.19.1
fqdn==1.5.1
h11==0.14.0
holoviews==1.18.3
httpcore==1.0.5
httpx==0.27.0
idna==3.7
ipykernel==6.29.4
ipython==8.24.0
isoduration==20.11.0
jedi==0.19.1
Jinja2==3.1.4
json5==0.9.25
jsonpointer==2.4
jsonschema==4.22.0
jsonschema-specifications==2023.12.1
jupyter-events==0.10.0
jupyter-lsp==2.2.5
jupyter_client==8.6.2
jupyter_core==5.7.2
jupyter_server==2.14.0
jupyter_server_terminals==0.5.3
jupyterlab==4.2.1
jupyterlab_pygments==0.3.0
jupyterlab_server==2.27.2
linkify-it-py==2.0.3
Markdown==3.6
markdown-it-py==3.0.0
MarkupSafe==2.1.5
matplotlib-inline==0.1.7
mdit-py-plugins==0.4.1
mdurl==0.1.2
mistune==3.0.2
nbclient==0.10.0
nbconvert==7.16.4
nbformat==5.10.4
nest-asyncio==1.6.0
notebook_shim==0.2.4
numpy==1.26.4
overrides==7.7.0
packaging==24.0
pandas==2.2.2
pandocfilters==1.5.1
panel==1.4.2
param==2.1.0
parso==0.8.4
pexpect==4.9.0
pillow==10.3.0
platformdirs==4.2.2
prometheus_client==0.20.0
prompt_toolkit==3.0.45
psutil==5.9.8
ptyprocess==0.7.0
pure-eval==0.2.2
pycparser==2.22
Pygments==2.18.0
python-dateutil==2.9.0.post0
python-json-logger==2.0.7
pytz==2024.1
pyviz_comms==3.0.2
PyYAML==6.0.1
pyzmq==26.0.3
referencing==0.35.1
requests==2.32.2
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
rpds-py==0.18.1
scipy==1.13.1
Send2Trash==1.8.3
six==1.16.0
sniffio==1.3.1
soupsieve==2.5
stack-data==0.6.3
terminado==0.18.1
tinycss2==1.3.0
tornado==6.4
tqdm==4.66.4
traitlets==5.14.3
types-python-dateutil==2.9.0.20240316
typing_extensions==4.12.0
tzdata==2024.1
uc-micro-py==1.0.3
uri-template==1.3.0
urllib3==2.2.1
wcwidth==0.2.13
webcolors==1.13
webencodings==0.5.1
websocket-client==1.8.0
xyzservices==2024.4.0

Complete, minimal, self-contained example code that reproduces the issue

https://holoviews.org/reference/streams/bokeh/Selection1D_tap.html

import numpy as np
import holoviews as hv
from holoviews import opts
from holoviews.streams import Selection1D
from scipy import stats
hv.extension('bokeh')

def gen_samples(N, corr=0.8):
    xx = np.array([-0.51, 51.2])
    yy = np.array([0.33, 51.6])
    means = [xx.mean(), yy.mean()]  
    stds = [xx.std() / 3, yy.std() / 3]
    covs = [[stds[0]**2          , stds[0]*stds[1]*corr], 
            [stds[0]*stds[1]*corr,           stds[1]**2]] 

    return np.random.multivariate_normal(means, covs, N)

data = [('Week %d' % (i%10), np.random.rand(), chr(65+np.random.randint(5)), i) for i in range(100)]
sample_data = hv.NdOverlay({i: hv.Points(gen_samples(np.random.randint(1000, 5000), r2))
                            for _, r2, _, i in data})
points = hv.Scatter(data, 'Date', ['r2', 'block', 'id']).redim.range(r2=(0., 1))
stream = Selection1D(source=points)
empty = (hv.Points(np.random.rand(0, 2)) * hv.Slope(0, 0)).relabel('No selection')

def regression(index):
    if not index:
        return empty
    scatter = sample_data[index[0]]
    xs, ys = scatter['x'], scatter['y']
    slope, intercep, rval, pval, std = stats.linregress(xs, ys)
    return (scatter * hv.Slope(slope, intercep)).relabel('r2: %.3f' % slope)

reg = hv.DynamicMap(regression, kdims=[], streams=[stream])

average = hv.Curve(points, 'Date', 'r2').aggregate(function=np.mean)
layout = points * average + reg
layout.opts(
    opts.Curve(color='black'),
    opts.Slope(color='black', framewise=True),
    opts.Scatter(color='block', tools=['tap', 'hover'], width=600, 
                 marker='triangle', cmap='Set1', size=10, framewise=True),
    opts.Points(frame_width=250),
    opts.Overlay(toolbar='above', legend_position='right')
)

Screencasts of the bug in action

This is the screencast with panel 1.3, where everything works as expected

panel_issue-2024-05-29_10.34.14.mp4

This is the screencast with panel 1.4.2, where the regression occurs (I didn't use 1.4.3 due to #6865 )

panel_issue-2024-05-29_10.38.49.mp4
@hoxbro
Copy link
Member

hoxbro commented May 29, 2024

This is a behavior change in Bokeh 3.4, see bokeh/bokeh#13831

@philippjfr
Copy link
Member

And will likely be fixed/reverted in bokeh 3.5.0. Will close.

@philippjfr philippjfr added the bokeh Request is for change in bokeh label May 30, 2024
@vindex10
Copy link

vindex10 commented Jun 13, 2024

Hi! I just wanted to share my workaround, which passes the Bokeh TapTool explicitly.

specifying mode="replace" is essential for now, until bokeh reverted the behavior. then, I expect it won't break anything to stay "explicit"

import numpy as np
import panel as pn
import bokeh
import holoviews as hv
from holoviews import opts
from holoviews import streams
hv.extension('bokeh')


ndoverlay = hv.NdOverlay({i: hv.Curve(np.arange(10)*i) for i in range(5)})

selection = streams.Selection1D(source=ndoverlay)
dmap = hv.DynamicMap(lambda index: ndoverlay[index] if index else ndoverlay.clone(),
                     kdims=[], streams=[selection])
layout = ndoverlay + dmap
tap_tool = bokeh.models.TapTool(mode="replace")
layout.opts(opts.Curve(tools=[tap_tool], line_width=10), opts.NdOverlay(legend_limit=0))

pn.panel(layout).servable()

based on: https://holoviews.org/reference/streams/bokeh/Selection1D.html

works with

  • bokeh==3.4.1
  • panel==1.4.4
  • holoviews==1.19.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bokeh Request is for change in bokeh
Projects
None yet
Development

No branches or pull requests

4 participants