☰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

Use a variable as argument to CustomJS

Community Supportcustomjs
Icoti
Icoti

CustomJS accepts arguments that are passed to javascript during callback.

Though, I observed that if I use a variable as argument to a CustomJS callback, then modify the value of the variable before triggering the callback, the callback uses an outdated value of the variable.
This is different from python callbacks, in which the current value of inputs variables are used.

Here is a short example comparing the behavior of Python and CustomJS callbacks, in which I also introduced what I see as a workaround for CustomJS to use an up to date argument, using a paragraph object to store the input (launch with bokeh serve --show):

from bokeh.io import curdoc
from bokeh.models import Button, Paragraph, CustomJS
from bokeh.layouts import column

js_code = """
alert("Input is: " + input +
", Input from paragraph is: " + paragraph.text)
"""

button_py = Button(label="Start python-callback")
button_js = Button(label="Start js-callback")

input = 1
paragraph = Paragraph(text=str(input))

def py_callback():
    print(f"Input is {input}")
    print(f"Input from paragraph is {paragraph.text}")

# Callbacks:
button_py.on_click(py_callback)
button_js.js_on_click(CustomJS(args=dict(input=input, paragraph=paragraph), code=js_code))

input = 2
paragraph.text = str(input)

curdoc().add_root(column(button_py, button_js))

The Python callback leads as expected to the print log:
“Input is 2
Input from paragraph is 2”
The CustomJS callback leads to “Input is: 1, Input from paragraph is: 2”, I had expected “Input is: 2, Input from paragraph is: 2”.

Is there another more straightforward way to dynamically update the arguments of CustomJS callbacks than passing them to a bokeh model?

My system:
Windows 10
Python 3.12.0
bokeh 3.3.0

⌁   Link to post
Bryan
Bryan

This is standard Python behavior, where variables are just names for values, and not references to memory:

>>> a = 10
>>> b = a
>>> b
10
>>> a = 20
>>> b # still 10
10

For what you are looking for, your best is probably to create a DataModel subclass. A DataModel is a very lightweight user-defined model, created with only a small amount of declarative Python, that can be synchronized across the Python ↔ JS boundary like any standard Bokeh object:

class Params(DataModel):
    foo = Float(default=0.1)
    bar = Int(default=10)

If you pass an instance of a Params to a CustomJS it will not be “evaluated” until right before it is serialized to generate the output. There is a complete example here:

https://github.com/bokeh/bokeh/blob/branch-3.4/examples/plotting/customjs_expr.py

⌁   Link to post
Icoti
Icoti

Based on the example you referred to, the implementation of DataModel to my example would be as follows:

from bokeh.core.properties import String, expr
from bokeh.model import  DataModel
from bokeh.io import curdoc
from bokeh.models import Button, CustomJS
from bokeh.layouts import column

js_code = """
alert("Input from DataModel is: " + Data_Model.text)
"""

button_py = Button(label="Start python-callback")
button_js = Button(label="Start js-callback")

input = 1
class string_buffer(DataModel):
    text = String()

file_content = string_buffer(text=str(input))

def py_callback():
    print(f"Input is from DataModel is {file_content.text}")

# Callbacks:
button_py.on_click(py_callback)
button_js.js_on_click(CustomJS(args=dict(Data_Model=file_content), code=js_code))

input = 2
file_content.text = str(input)

curdoc().add_root(column(button_py, button_js))
⌁   Link to post

End of archived discussion · Replies are disabled