Sure @Bryan , attaching the python code I am locally running on my laptop
bokeh-events-server-app.py :
""" Demonstration Bokeh app of how to register event callbacks in both
Javascript and Python using an adaptation of the color_scatter example
from the bokeh gallery. This example extends the js_events.py example
with corresponding Python event callbacks.
"""
import numpy as np
from bokeh import events
from bokeh.io import curdoc
from bokeh.layouts import column, row
from bokeh.models import Button, CustomJS, Div
from bokeh.plotting import figure
def display_event(div, attributes=[]):
"""
Function to build a suitable CustomJS to display the current event
in the div model.
"""
style = 'float: left; clear: left; font-size: 13px'
return CustomJS(args=dict(div=div), code=f"""
const {{to_string}} = Bokeh.require("core/util/pretty")
const attrs = {attributes};
const args = [];
for (let i = 0; i<attrs.length; i++ ) {{
const val = to_string(cb_obj[attrs[i]], {{precision: 2}})
args.push(attrs[i] + '=' + val)
}}
const line = "<span style={style!r}><b>" + cb_obj.event_name + "</b>(" + args.join(", ") + ")</span>\\n";
const text = div.text.concat(line);
const lines = text.split("\\n")
if (lines.length > 35)
lines.shift();
div.text = lines.join("\\n");
""")
def print_event(attributes=[]):
"""
Function that returns a Python callback to pretty print the events.
"""
print("inside call back wrapper...")
def python_callback(event):
cls_name = event.__class__.__name__
attrs = ', '.join([f"{attr}={event.__dict__[attr]}" for attr in attributes])
print(f"{cls_name}({attrs})")
return python_callback
# Follows the color_scatter gallery example
N = 4000
x = np.random.random(size=N) * 100
y = np.random.random(size=N) * 100
radii = np.random.random(size=N) * 1.5
colors = np.array([(r, g, 150) for r, g in zip(50+2*x, 30+2*y)], dtype="uint8")
p = figure(tools="pan,wheel_zoom,zoom_in,zoom_out,reset,tap,lasso_select,box_select,box_zoom,undo,redo")
p.circle(x, y, radius=radii, fill_color=colors, fill_alpha=0.6, line_color=None)
# Add a div to display events and a button to trigger button click events
div = Div(width=1000)
button = Button(label="Button", button_type="success", width=300)
layout = column(button, row(p, div))
point_attributes = ['x','y','sx','sy']
pan_attributes = [*point_attributes, 'delta_x', 'delta_y']
pinch_attributes = [*point_attributes, 'scale']
wheel_attributes = [*point_attributes, 'delta']
## Register Javascript event callbacks
# Point events
p.js_on_event(events.Tap, display_event(div, attributes=point_attributes))
p.js_on_event(events.DoubleTap, display_event(div, attributes=point_attributes))
p.js_on_event(events.Press, display_event(div, attributes=point_attributes))
# Point events
p.on_event('Tap', print_event(attributes=point_attributes))
p.on_event(events.DoubleTap, print_event(attributes=point_attributes))
p.on_event(events.Press, print_event(attributes=point_attributes))
curdoc().add_root(layout)
bokeh serve command :
❯ bokeh serve --show bokeh-events-server-app.py
2024-04-12 14:41:29,650 Starting Bokeh server version 3.4.0 (running on Tornado 6.4)
2024-04-12 14:41:29,653 User authentication hooks NOT provided (default user enabled)
2024-04-12 14:41:29,655 Bokeh app running at: http://localhost:5006/bokeh-events-server-app
2024-04-12 14:41:29,655 Starting Bokeh server with process id: 37384
inside call back wrapper...
inside call back wrapper...
inside call back wrapper...
2024-04-12 14:41:30,073 WebSocket connection opened
2024-04-12 14:41:30,073 ServerConnection created
pip freeze :
❯ pip freeze
asttokens==2.4.1
black==24.3.0
bokeh==3.4.0
cachetools==5.3.3
certifi==2024.2.2
charset-normalizer==3.3.2
click==8.1.7
comm==0.2.2
contourpy==1.2.1
db-dtypes==1.2.0
decorator==5.1.1
executing==2.0.1
google-api-core==2.18.0
google-auth==2.29.0
google-cloud-bigquery==3.20.1
google-cloud-core==2.4.1
google-crc32c==1.5.0
google-resumable-media==2.7.0
googleapis-common-protos==1.63.0
grpcio==1.62.1
grpcio-status==1.62.1
idna==3.6
ipython==8.23.0
ipywidgets==8.1.2
jedi==0.19.1
Jinja2==3.1.3
jupyter_bokeh==4.0.1
jupyterlab_widgets==3.0.10
MarkupSafe==2.1.5
matplotlib-inline==0.1.6
mypy-extensions==1.0.0
networkx==3.3
numpy==1.26.4
packaging==24.0
pandas==2.2.1
parso==0.8.4
pathspec==0.12.1
pexpect==4.9.0
pillow==10.3.0
platformdirs==4.2.0
prompt-toolkit==3.0.43
proto-plus==1.23.0
protobuf==4.25.3
ptyprocess==0.7.0
pure-eval==0.2.2
pyarrow==15.0.2
pyasn1==0.6.0
pyasn1_modules==0.4.0
Pygments==2.17.2
python-dateutil==2.9.0.post0
pytz==2024.1
PyYAML==6.0.1
requests==2.31.0
rsa==4.9
setuptools==69.2.0
six==1.16.0
stack-data==0.6.3
tornado==6.4
traitlets==5.14.2
tzdata==2024.1
urllib3==2.2.1
wcwidth==0.2.13
widgetsnbextension==4.0.10
xyzservices==2024.4.0
Browser : Google Chrome : Version 123.0.6312.122 (Official Build) (arm64)