I am using a Bokeh 3.4.3 server and I am running into an issue where the active_scroll property is not updated when the WheelZoom tool is toggled. Is this a known issue? If so, are there any workarounds? In my real application, I have multiple figures and I am trying to determine from Python whether a WheelZoom tool is active by checking the active_scroll property, but it is not returning accurate results.
Thanks in advance,
Alex
from bokeh.plotting import figure, curdoc
from bokeh.layouts import column
from bokeh.models import Button
import numpy as np
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x)
p = figure(
width=600,
height=400,
active_scroll=None
)
p.line(x, y, line_width=2)
p.scatter(x[::5], y[::5], size=8, color=‘red’, alpha=0.6)
def on_active_scroll_change(attr, old, new):
print(f"Active scroll changed!“)
print(f” Old value: {old}“)
print(f” New value: {new}")
p.toolbar.on_change(‘active_scroll’, on_active_scroll_change)
def check_state():
print(f"Active scroll: {p.toolbar.active_scroll}")
current_scroll = p.toolbar.active_scroll
check_button = Button(label=“Check Current Active Scroll”, width=200)
check_button.on_click(check_state)
layout = column(
p,
check_button
)
curdoc().add_root(layout)
@ah7149407 the “active” properties on the toolbar, e.g. active_scroll, are up-front configuration options for specifying what should happen during plot initialization. From the reference guide
Specify a scroll/pinch tool to be active when the plot is displayed.
They are not expected to update their values after initialization. It’s possible the docs could be made more clear on this point, I suppose.
However, individual tool instances for tools like WheelZoomTool have their own active property that should tell you what you want, as well as update when the tool itself is activated or de-activated.
I don’t see an ‘active’ attribute in the documentation for WheelZoomTool for Bokeh 2.4.2, and I get an AttributeError when trying to access it in Python.
Is this the correct usage?
wheel_zoom = [
tool for tool in p.tools if isinstance(tool, WheelZoomTool)
][0]
if wheel_zoom.active:
wheel_zoom.active = False
Apologies I did not look at the source code closely enough. Tool.active is an “internal” property that is not exposed to the Python side. I expect this is the case because early days there wasn’t any capability to have “readonly properties” that could be used to report out status, but not be set by users. [1] Nowadays it would be simple to have a readonly property that reports the information you want, but apparently no one ever asked about it before now, so it was never done.
All I can suggest is to make a GitHub Issue to request this as a new feature in a future release. Unfortunately I don’t have any good workaround suggestions.
We don’t want Tool.active to be settable by users because managing tool states when there are competing gestures is actually somewhat complicated and needs to be mediated at a higher level, i.e. by the toolbar that knows about all the currently configured tools. ↩︎
We are trying to create keyboard shortcuts for toggling different figure tools for individual/all figures in a document in our application. Setting active_scroll or active_drag from Python does seem to turn on/off the respective tool even after the figures are already displayed. The trouble comes when manually clicking the figure toolbar button, which doesn’t set active_scroll/active_drag. Is there any way for us to intercept the click action on a figure tool (e.g., wheel zoom, box zoom, pan) and trigger a Python callback to manually do the bookkeeping of which tools are active/inactive?
Is there any way for us to intercept the click action on a figure tool (e.g., wheel zoom, box zoom, pan) and trigger a Python callback to manually do the bookkeeping of which tools are active/inactive?
Nothing is impossible, but this would not be trivial an I don’t have any example code to share All I can do is sketch a possible approach at a high level:
add a “document init” CustomJS callback, in this callback:
search through the document models to find your wheel zoom tool
use the the BokehJS connect mechanism to hook up a JS callback to the internal active property. e.g. refer to the many connect_signals methods for examples of its use. It will be something along the lines of
tool.connect(tool.properties.active.change, () => { ...code here })
in this active callback, set some property that you want to use to trigger a Python callback
cc @mateusz in case he has any more concrete advice than this
During further testing, we also noticed occurrences of WheelZoomTool/BoxZoomTool/PanTool not becoming activated/deactivated when setting active_scroll/active_drag as well as occurrences of active_scroll being changed when active_drag is set, and vice versa. I don’t have instructions at this time for how to reproduce these cases, but it seems we are able to work-around them. I will include them in the GH issue as well just in case.
Thanks again for the support. We really appreciate it.