Js_on_change vs on_change

Hello,

I wanted to know if there are differences I should be aware of between js_on_change and on_change for selections. Here is a simple example motivated from the Callbacks for selection

I verified that the selection works as intended for both approaches. The second one is much easier for me since I do not know JavaScript. Are both equally valid?

Thanks in advance

from random import random
from bokeh.layouts import row
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.plotting import figure, output_file, curdoc
import numpy as np

output_file("callback.html")

x = [random() for x in range(500)]
y = [random() for y in range(500)]

s1 = ColumnDataSource(data=dict(x=x, y=y))
p1 = figure(width=400, height=400, tools="lasso_select", title="Select Here")
p1.circle('x', 'y', source=s1, alpha=0.6)

s2 = ColumnDataSource(data=dict(x=[], y=[]))
p2 = figure(width=400, height=400, x_range=(0, 1), y_range=(0, 1),
            tools="", title="Watch Here")
p2.circle('x', 'y', source=s2, alpha=0.6)

s1.selected.js_on_change('indices', CustomJS(args=dict(s1=s1, s2=s2), code="""
        const inds = cb_obj.indices;
        const d1 = s1.data;
        const d2 = s2.data;
        d2['x'] = []
        d2['y'] = []
        for (let i = 0; i < inds.length; i++) {
            d2['x'].push(d1['x'][inds[i]])
            d2['y'].push(d1['y'][inds[i]])
        }
        s2.change.emit();
    """)
)

#def add_selection(attr, old, new):   
#    s2.data = dict(x = np.array(s1.data['x'])[new], 
#        y = np.array(s1.data['y'])[new])
#s1.selected.on_change('indices', add_selection)

layout = row(p1, p2)
curdoc().add_root(layout)

on_change can only by used in Bokeh server applications. js_on_change can be used with any kind of output, including static HTML (no Bokeh server anywhere). That’s really the only differentiator. [1]


  1. And even that distinction is fading, as projects like Pyodide and Pyscript make “Python in the browser” a more realistic idea. ↩︎