Reputation: 2381
I am working on a bokeh visualisation, one requirement is that it runs without a server, as such I am using CustomJS
to implement interactivity on the client side using javascript. Passing ColumnDataSource
s to CustomJS
works fine to update plots interactively.
What I cannot do however, is just embed some arbitrary json
data into the output html. See the self contained example below:
from bokeh.io import output_file
from bokeh.layouts import widgetbox
from bokeh.models import CustomJS
from bokeh.models.widgets import Div, Button
from bokeh.plotting import show
data_for_client = {
"x": 3,
"y": {
"foo": [1, 2, 3],
"bar": {"some_bar": "doge", "other bar": "much json"}
},
"z": [[1, 2], [3, 4]]
}
callback = CustomJS(args={"data_for_client": data_for_client}, code="""
console.log(data_for_client);
""")
content = widgetbox(
Button(label="click here", callback=callback),
Div(text="some complicated interactive stuff based on json content here")
)
output_file("issue.html")
show(content)
In my case, the data_for_client
is a complicated deeply nested json
, different parts of this json
are used depending on user interaction with some widgets.
I do not need to make any modifications to the json
data based on user interaction, or attach any listeners or anything special. I just need the content of the json value to be available in the CustomJS
callback.
For simple column data, I can wrap my data in a ColumnDataSource
and pass that as an arg to CustomJS
, however I do not find anything similar for plain json
data. The code above fails with message:
ValueError: expected an element of Dict(String, Instance(Model)), got {'data_for_client': {'x': 3, 'y': {'foo': [1, 2, 3], 'bar': {'some_bar': 'doge', 'other bar': 'much json'}}, 'z': [[1, 2], [3, 4]]}}
Upvotes: 1
Views: 1958
Reputation: 1775
You can pass it as a string, I would expect that there is stuff in javascript to read json data from a json string, I know this exists in python at least.
from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models import CustomJS, ColumnDataSource
from bokeh.models.widgets import Div, Button
import json
data_for_client = {
"x": [3],
"y": {
"foo": [1, 2, 3],
"bar": {"some_bar": "doge", "other bar": "much json"}
},
"z": [[1, 2], [3, 4]],
}
json_string = json.dumps(data_for_client)
DumButton = Button(label=json_string)
# Here is the change:
callback = CustomJS(args={"db":DumButton}, code="""
console.log(db.label);
var test=JSON.parse(db.label);
console.log(test);
for(key in test){console.log(test[key])}
""")
content = widgetbox(
Button(label="click here", callback=callback),
)
show(content)
Upvotes: 2
Reputation: 468
You need to change the first data_for_client
to "data_for_client"
in the related line, because otherwise you cannot use a dictionary ({...}) as a dictionary-key:
from bokeh.io import output_file
from bokeh.layouts import widgetbox
from bokeh.models import CustomJS
from bokeh.models.widgets import Div, Button
from bokeh.plotting import show
data_for_client = {
"x": 3,
"y": {
"foo": [1, 2, 3],
"bar": {"some_bar": "doge", "other bar": "much json"}
},
"z": [[1, 2], [3, 4]]
}
# Here is the change:
callback = CustomJS(args={"data_for_client": data_for_client}, code="""
console.log(data_for_client);
""")
content = widgetbox(
Button(label="click here", callback=callback),
Div(text="some complicated interactive stuff based on json content here")
)
output_file("issue.html")
show(content)
Upvotes: 2