☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Transform on_change into JS callbacks

Community Supportcustomjsserverbokeh
Charlie
Charlie

Hello,

I’m not very familiar with JAVA and I’m having some problems writing this program as ‘.html’.
This small example shows the following functionality:

Imports:

import pandas as pd
import numpy as np
import random

from bokeh.models import (ColumnDataSource,
Toggle,CustomJS,HoverTool, Select,
Button, TextInput, LabelSet,
CheckboxGroup, DataTable, TableColumn
)

from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import column, row

Data:

x = random.sample(range(10, 30), 10)
y = random.sample(range(40, 70), 10)
z = random.sample(range(70, 100),10)
l = [‘P’+str(n) for n in range(len(z))]
c = [‘skyblue’]*len(x)
cl= [‘c1’]*4 + [‘c2’]*3 + [‘c3’]*3

dataf = pd.DataFrame({‘Var1’: x, ‘Var2’: y, ‘Var3’: z, ‘Label’: l, ‘color’: c, ‘class’: cl} )

Predefined issues:

HOVER_TOOLTIPS = HoverTool(tooltips=
[(“Label”, “@l”),
(‘Var-1’, ‘@x’ ),
(‘Var-2’, ‘@y’ ),
(‘Var-3’, ‘@z’ ),
])

axis_map = {
“Variable-1”: “Var1”,
“Variable-2”: “Var2”,
“Variable-3”: “Var3”
}

class_map = {
‘Class-1’: ‘c1’,
‘Class-2’: ‘c2’,
‘Class-3’: ‘c3’,
}

Code:

source = ColumnDataSource(data=dict(x=,
y=,
z=,
l=,
c=
))

p1 = figure(plot_width=800, plot_height=700,
tools=[HOVER_TOOLTIPS,
“tap,pan,lasso_select,wheel_zoom,save,reset”],
toolbar_location=“above”,
)

p1.circle(x=“x”, y=“y”,color=‘c’ ,fill_alpha=0.8 ,source=source, size=10,
selection_line_color=“darkblue”)

Labels button:

labels = LabelSet(x=‘x’, y=‘y’, text=‘l’,
x_offset=5, y_offset=5, source=source, render_mode=‘canvas’,visible=False)
p1.add_layout(labels)
button = Toggle(label=‘Labels’, button_type=“primary”, active=False)

Table:

columns = [TableColumn(field=n,title=n) for n in [‘Var1’,‘Var2’,‘Var3’,‘Label’]]
table = DataTable(source=source,columns=columns, width=800, height=300)

Axis:

x_axis = Select(title=“X Axis”, options=sorted(axis_map.keys()), value=“Variable-1”)
y_axis = Select(title=“Y Axis”, options=sorted(axis_map.keys()), value=“Variable-2”)

Finder:

finder = TextInput(title=“Finder”)

Classes:

class_selection = CheckboxGroup(labels=list(class_map.keys()), active = )

def select_pulsar():

selected = dataf.copy()
    
class_to_paint = [class_map[class_selection.labels[i]] for i in class_selection.active]
for name in class_to_paint:
    if name == 'c1':
        selected.loc[selected['class'] == 'c1','color'] = 'orange'
    
    if name == 'c2':
        selected.loc[selected['class'] == 'c2','color'] = 'yellow' 

    if name == 'c3':
        selected.loc[selected['class'] == 'c3','color'] = 'green' 
        
finder_value = finder.value.strip()
if (finder_value != ""):
    selected.loc[selected.Label==finder_value,'color'] = 'red'
        
return selected

def update():
df = select_pulsar()
update_table(df)

x_var = axis_map[x_axis.value]
y_var = axis_map[y_axis.value]

p1.xaxis.axis_label = x_axis.value
p1.yaxis.axis_label = y_axis.value

source.data = dict(
    x=df[x_var],
    y=df[y_var],
    z=df['Var3'],
    l=df['Label'],
    c=df['color']
)

def update_table(data):
table.source = ColumnDataSource(data)

def selection_change(attrname, old, new):
data = dataf.copy()
selected = source.selected.indices
if selected:
data = data.iloc[selected, :]

update_table(data)

Callbacks:

source.selected.on_change(‘indices’, selection_change) #Selected pulsars

button.js_link(‘active’, labels, ‘visible’) #Button

class_selection.on_change(‘active’, lambda attr, old, new: update()) #Classes

FINDERS = [x_axis, y_axis, finder] axis and finder

for control in FINDERS:
control.on_change(‘value’, lambda attr, old, new: update())

Display:

BUTTONS = [button,x_axis, y_axis, finder, class_selection]

inputs = column(*BUTTONS, width=220)

display = column(row(inputs, column(p1,table)))

update() # Initial loading

curdoc().add_root(display)

  • Display the labels associated with each value using ‘Toggle’.
  • Display in the table the values selected in the figure with both ‘tap’ and ‘lasso select’.
  • Change the variables that define the axes with ‘Select’.
  • Indicate in another color the value determined in ‘TextInput’ by introducing the label associated with each value. This is defined in the data frame as ‘Label’.
  • Change the color of the values according to their class through ‘CheckboxGroup’. This is defined in the data frame as ‘class’.

The ‘Toggle’ functionality has been easy for me to describe but I’m quite lost with the rest.

Any idea how to transform these functionalities by avoiding ‘.on_change’?

Thanks a lot for the help and attention.[quote=“Charlie, post:1, topic:9148, full:true”]
Hello,

I’m not very familiar with JAVA and I’m having some problems writing this program as ‘.html’.
This small example shows the following functionality:

import pandas as pd
import numpy as np
import random

from bokeh.models import (ColumnDataSource,
Toggle,CustomJS,HoverTool, Select,
Button, TextInput, LabelSet,
CheckboxGroup, DataTable, TableColumn
)

from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import column, row

x = random.sample(range(10, 30), 10)
y = random.sample(range(40, 70), 10)
z = random.sample(range(70, 100),10)
l = [‘P’+str(n) for n in range(len(z))]
c = [‘skyblue’]*len(x)
cl= [‘c1’]*4 + [‘c2’]*3 + [‘c3’]*3

dataf = pd.DataFrame({‘Var1’: x, ‘Var2’: y, ‘Var3’: z, ‘Label’: l, ‘color’: c, ‘class’: cl} )

HOVER_TOOLTIPS = HoverTool(tooltips=
[(“Label”, “@l”),
(‘Var-1’, ‘@x’ ),
(‘Var-2’, ‘@y’ ),
(‘Var-3’, ‘@z’ ),
])

axis_map = {
“Variable-1”: “Var1”,
“Variable-2”: “Var2”,
“Variable-3”: “Var3”
}

class_map = {
‘Class-1’: ‘c1’,
‘Class-2’: ‘c2’,
‘Class-3’: ‘c3’,
}

source = ColumnDataSource(data=dict(x=,
y=,
z=,
l=,
c=
))

p1 = figure(plot_width=800, plot_height=700,
tools=[HOVER_TOOLTIPS,
“tap,pan,lasso_select,wheel_zoom,save,reset”],
toolbar_location=“above”,
)

p1.circle(x=“x”, y=“y”,color=‘c’ ,fill_alpha=0.8 ,source=source, size=10,
selection_line_color=“darkblue”)

labels = LabelSet(x=‘x’, y=‘y’, text=‘l’,
x_offset=5, y_offset=5, source=source, render_mode=‘canvas’,visible=False)
p1.add_layout(labels)
button = Toggle(label=‘Labels’, button_type=“primary”, active=False)

columns = [TableColumn(field=n,title=n) for n in [‘Var1’,‘Var2’,‘Var3’,‘Label’]]

table = DataTable(source=source,columns=columns, width=800, height=300)

x_axis = Select(title=“X Axis”, options=sorted(axis_map.keys()), value=“Variable-1”)
y_axis = Select(title=“Y Axis”, options=sorted(axis_map.keys()), value=“Variable-2”)

finder = TextInput(title=“Finder”)

class_selection = CheckboxGroup(labels=list(class_map.keys()), active = )

def select_pulsar():

selected = dataf.copy()
    
class_to_paint = [class_map[class_selection.labels[i]] for i in class_selection.active]
for name in class_to_paint:
    if name == 'c1':
        selected.loc[selected['class'] == 'c1','color'] = 'orange'
    
    if name == 'c2':
        selected.loc[selected['class'] == 'c2','color'] = 'yellow' 

    if name == 'c3':
        selected.loc[selected['class'] == 'c3','color'] = 'green' 
        
finder_value = finder.value.strip()
if (finder_value != ""):
    selected.loc[selected.Label==finder_value,'color'] = 'red'
        
return selected

def update():
df = select_pulsar()
update_table(df)

x_var = axis_map[x_axis.value]
y_var = axis_map[y_axis.value]

p1.xaxis.axis_label = x_axis.value
p1.yaxis.axis_label = y_axis.value

source.data = dict(
    x=df[x_var],
    y=df[y_var],
    z=df['Var3'],
    l=df['Label'],
    c=df['color']
)

def update_table(data):
table.source = ColumnDataSource(data)

def selection_change(attrname, old, new):
data = dataf.copy()
selected = source.selected.indices
if selected:
data = data.iloc[selected, :]

update_table(data)

source.selected.on_change(‘indices’, selection_change)

button.js_link(‘active’, labels, ‘visible’)

class_selection.on_change(‘active’, lambda attr, old, new: update())

FINDERS = [x_axis, y_axis, finder] axis and finder

for control in FINDERS:
control.on_change(‘value’, lambda attr, old, new: update())

BUTTONS = [button,x_axis, y_axis, finder, class_selection]

inputs = column(*BUTTONS, width=220)

display = column(row(inputs, column(p1,table)))

update()

curdoc().add_root(display)

  • Display the labels associated with each value using ‘Toggle’.
  • Display in the table the values selected in the figure with both ‘tap’ and ‘lasso select’.
  • Change the variables that define the axes with ‘Select’.
  • Indicate in another color the value determined in ‘TextInput’ by introducing the label associated with each value. This is defined in the data frame as ‘Label’.
  • Change the color of the values according to their class through ‘CheckboxGroup’. This is defined in the data frame as ‘class’.

The ‘Toggle’ functionality has been easy for me to describe but I’m quite lost with the rest.

Any idea how to transform these functionalities by avoiding ‘.on_change’?

I have tried to paste the code as best as possible, any advice on how to do this task better is welcome. Apologies in advance if it is not entirely intelligible.

Thanks a lot for the help and attention.

⌁   Link to post
Charlie
Charlie

Hi, sorry for the previous format. I hope it reads better now.

import pandas as pd
import numpy as np
import random

from bokeh.models import (ColumnDataSource, 
                          Toggle,CustomJS,HoverTool, Select, 
                          Button, TextInput, LabelSet,
                          CheckboxGroup,  DataTable, TableColumn
                         )

from bokeh.plotting import figure, curdoc, show
from bokeh.layouts import column, row



## Data:

x = random.sample(range(10, 30), 10)
y = random.sample(range(40, 70), 10)
z = random.sample(range(70, 100),10)
l = ['P'+str(n) for n in range(len(z))]
c = ['skyblue']*len(x)
cl= ['c1']*4 + ['c2']*3 + ['c3']*3

dataf = pd.DataFrame({'Var1': x, 'Var2': y, 'Var3': z, 'Label': l, 'color': c, 'class': cl} )

HOVER_TOOLTIPS = HoverTool(tooltips=
                 [("Label",      "@l"),
                  ('Var-1',      '@x' ),
                  ('Var-2',      '@y' ),
                  ('Var-3',      '@z' ),
                 ])

axis_map = {
    "Variable-1": "Var1",
    "Variable-2": "Var2",
    "Variable-3": "Var3"
}

class_map = {
    'Class-1': 'c1',
    'Class-2': 'c2',
    'Class-3': 'c3',
}

source = ColumnDataSource(data=dict(x=[],
                                    y=[],
                                    z=[],
                                    l=[],
                                    c=[]
                                   ))

p1 = figure(plot_width=800, plot_height=700,
            tools=[HOVER_TOOLTIPS,
                   "tap,pan,lasso_select,wheel_zoom,save,reset"],
            toolbar_location="above",
           )


p1.circle(x="x", y="y",color='c' ,fill_alpha=0.8 ,source=source, size=10,
           selection_line_color="darkblue")

##################################################################################


# Labels button:
labels = LabelSet(x='x', y='y', text='l',
              x_offset=5, y_offset=5, source=source, render_mode='canvas',visible=False)
p1.add_layout(labels)
button = Toggle(label='Labels', button_type="primary", active=False)

# Table:
columns = [TableColumn(field=n,title=n) for n in ['Var1','Var2','Var3','Label']]
table = DataTable(source=source,columns=columns, width=800, height=300)

# Axis:
x_axis = Select(title="X Axis", options=sorted(axis_map.keys()), value="Variable-1")
y_axis = Select(title="Y Axis", options=sorted(axis_map.keys()), value="Variable-2")

# Finder:
finder = TextInput(title="Finder")

# Classes:
class_selection = CheckboxGroup(labels=list(class_map.keys()), active = [])


def select_pulsar():

    selected = dataf.copy()
        
    class_to_paint = [class_map[class_selection.labels[i]] for i in class_selection.active]
    for name in class_to_paint:
        if name == 'c1':
            selected.loc[selected['class'] == 'c1','color'] = 'orange'
        
        if name == 'c2':
            selected.loc[selected['class'] == 'c2','color'] = 'yellow' 

        if name == 'c3':
            selected.loc[selected['class'] == 'c3','color'] = 'green' 
            
    finder_value = finder.value.strip()
    if (finder_value != ""):
        selected.loc[selected.Label==finder_value,'color'] = 'red'
            
    return selected


def update():
    df = select_pulsar()
    update_table(df) 

    x_var = axis_map[x_axis.value]
    y_var = axis_map[y_axis.value]
    
    p1.xaxis.axis_label = x_axis.value
    p1.yaxis.axis_label = y_axis.value
    
    source.data = dict(
        x=df[x_var],
        y=df[y_var],
        z=df['Var3'],
        l=df['Label'],
        c=df['color']
    )
    
def update_table(data):
    table.source = ColumnDataSource(data)
    
        
def selection_change(attrname, old, new):
    data = dataf.copy()
    selected = source.selected.indices
    if selected:
        data = data.iloc[selected, :]
        
    update_table(data)

### Callbacks:

source.selected.on_change('indices', selection_change) #Selected pulsars


button.js_link('active', labels, 'visible') #Button


class_selection.on_change('active', lambda attr, old, new: update()) #Classes

FINDERS = [x_axis, y_axis, finder] #Axis and finder

for control in FINDERS:
    control.on_change('value', lambda attr, old, new: update())
    
    
### Display:
BUTTONS = [button,x_axis, y_axis, finder, class_selection]

inputs = column(*BUTTONS, width=220)

display = column(row(inputs, column(p1,table)))



update()  # Initial loading 


curdoc().add_root(display)



As I commented the above, I have hardly worked in Java and I have some problems seeing how to adapt functionalities developed only with purely python callbacks to Java format.
I have some ideas but I’m still not clear on how to do them.

Any help is welcome but anyway, thank you very much for everything.

⌁   Link to post

End of archived discussion · Replies are disabled