Search code examples
pythonbokeh

How to make Bokeh button invoke a function (using CustomJS)


I am able to get the functionality with curdoc option and then using 'bokeh serve bokehcode.py' and then having my flask code (call it app.py) refer to this bokeh plot. But I need to have a single python code that includes bokeh part as well, and I am running in to an issue in making the button click to invoke the function that updates my plot/figure. I have spent the whole day without much luck.

For the sake of simplicity i have removed all the functionality (even the Flask part) and put a simplified code below, which I need working without curdoc option (so mostly with customjs callback?). I can then extend it to my functionality.

from bokeh.models.widgets import TextInput,Button,Paragraph
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.plotting import figure

inptxt = TextInput()
displaytxt = Paragraph()
button = Button()

p = figure(plot_width=400, plot_height=400)
def myfunc():
    displaytxt.text=inptxt.value
    p.xaxis.axis_label = inptxt.value

button.on_click(myfunc)
layout=column(inptxt,displaytxt,button,p)

curdoc().add_root(layout)

In my actual code there will be a lot things 'myfunc()' will do, including some machine learning stuff and then it will update the plots. I would like this myfunc to be invoked when the button is clicked and also update the figure(p), and i would like it to be achieved without using curdoc. Any help on how to do this is greatly appreciated.


Solution

  • from bokeh.layouts import column
    from bokeh.models import CustomJS, TextInput, Button, Paragraph
    from bokeh.plotting import figure, show
    
    inptxt = TextInput()
    displaytxt = Paragraph()
    button = Button()
    
    p = figure(plot_width=400, plot_height=400,
               # Note that without setting the initial label,
               # setting it with the button will not make it
               # visible unless you interact with the plot, e.g.
               # by panning it. I've created
               # https://github.com/bokeh/bokeh/issues/10362
               # for this.
               x_axis_label='hello')
    p.circle(0, 0)  # To avoid having a blank plot.
    
    
    def myfunc():
        displaytxt.text = inptxt.value
        p.xaxis.axis_label = inptxt.value
    
    
    button.js_on_click(CustomJS(args=dict(inptxt=inptxt,
                                          displaytxt=displaytxt,
                                          # Need `[0]` because `p.xaxis` is actually
                                          # a "splattable list" that BokehJS doesn't support.
                                          xaxis=p.xaxis[0]),
                                code="""\
                                    displaytxt.text = inptxt.value;
                                    xaxis.axis_label = inptxt.value;
                                """))
    show(column(inptxt, displaytxt, button, p))