There’s at least one definite issue, and a suggestion for a different approach that I would take.
The first issue is that the args
dict cannot pass arbitrary values [1]. The only thing that it can synchronize is other Bokeh models. So you can’t pass the encoded audio data that way (but also don’t need to, see next point).
The other comment I would make is that it is always the best practice with Bokeh to make the smallest change possible. In concrete terms that usually mean: change a property on an existing model, don’t replace models wholesale. And very specifically here, that means updating the code
property of the existing callback, not making a new callback. (I’m not actually sure if swapping out the CustomJS
callback works, I changed to how I would actually write things in practice before even trying). Below is a complete updated example:
from bokeh.plotting import curdoc
from bokeh.layouts import row
from bokeh.models.widgets import Button
from bokeh.events import ButtonClick
from bokeh.models.callbacks import CustomJS
import logging
bokehlog = logging.getLogger("deepsong")
bokehlog.setLevel(logging.INFO)
CODE = """
const aud = document.getElementById("audio_tag")
aud.src="data:audio/wav;base64,"+%r
console.log(aud.src)
aud.play();
"""
callback = CustomJS(code=CODE % "hide-and-seek")
play_audio = Button(label='play audio')
play_audio.js_on_event(ButtonClick, callback)
def change_audio_callback():
bokehlog.info("entering `change_audio_callback`")
callback.code = CODE % "peek-a-boo"
change_audio = Button(label='change audio')
change_audio.on_click(change_audio_callback)
curdoc().add_root(row(play_audio, change_audio))
-
Though note there is an open issue, hopefully implemented soon, to add a “Namespace” model that would make it simple to send fairly arbitrary data via
args
. Once that is available, the code can remain fixed, more like your original code, and you could just update a property you define on the namespace model for the audio data. ↩︎