11

I want to send additional data to a bokeh event handler (e.g. an on_change or on_click method). A minimal example that increments or decrements an integer is below (I run this app with 'bokeh serve --show app.py). I had to write separate event handlers that do almost identical things in this example. To write this app with just one event handler function, I need to pass additional data or the event handler must know the calling object. How do I do that?

from bokeh.plotting import curdoc
from bokeh.models.widgets import Button, Paragraph
from bokeh.layouts import widgetbox

minus = Button(label='-')
plus = Button(label='+')
text = Paragraph(text='0')

def minus_callback():
    text.text = str(int(text.text) - 1)

def plus_callback():
    text.text = str(int(text.text) + 1)

minus.on_click(minus_callback)
plus.on_click(plus_callback)
# I would prefer to just use one callback and pass additional data to it:
# minus.on_click(callback, action='decrement')
# plus.on_click(callback, action='increment')

layout = widgetbox(minus, plus, text)
curdoc().add_root(layout)
Russell Burdt
  • 2,391
  • 2
  • 19
  • 30

2 Answers2

17

The standard functools.partial facility that is built into python works fine with Bokeh callbacks.

from functools import partial
from bokeh.plotting import curdoc
from bokeh.models.widgets import Button, Paragraph
from bokeh.layouts import widgetbox

minus = Button(label='-')
plus = Button(label='+')
text = Paragraph(text='0')

def callback(foo):
    print(foo)

minus.on_click(partial(callback, foo="minus"))
plus.on_click(partial(callback, foo="plus"))

layout = widgetbox(minus, plus, text)
curdoc().add_root(layout)
bigreddot
  • 33,642
  • 5
  • 69
  • 122
  • Thanks for this answer - functools partial also works well with Bokeh FunctionHandler to pass kwargs when running a server application within Jupyter, so the function in [this](https://github.com/bokeh/bokeh/blob/0.12.5/examples/howto/server_embed/notebook_embed.ipynb) code could have variables passed to it... – b2002 Oct 22 '17 at 21:45
  • How can we make it work with `on_change` with `attr="value"`? – harvpan Apr 30 '19 at 16:40
  • `attr` is a parameter of `on_change`, not of the callback. It always has to be supplied: `plus.on_change('value', partial(callback, foo="plus"))` – bigreddot Apr 30 '19 at 18:45
  • I am trying to pass a pandas dataframe as input parameters - but I got "TypeError: 'DataFrame' objects are mutable, thus they cannot be hashed" - code snipped: https://gist.github.com/6f5f20a270d6ecb92afd22be22edfa83 should I open a new question? – epifanio Aug 07 '20 at 14:05
0

Extending on @bigreddot's answer, this code outputs the updated value to the text attribute of the Paragraph object.

from functools import partial
from bokeh.plotting import curdoc
from bokeh.models.widgets import Button, Paragraph
from bokeh.layouts import column


def callback(update):
    text.text = str(int(text.text) + update)


minus = Button(label='-')
plus = Button(label='+')
text = Paragraph(text='0')
minus.on_click(partial(callback, update=-1))
plus.on_click(partial(callback, update=+1))

layout = column(minus, plus, text)
curdoc().add_root(layout)
Steven C. Howell
  • 16,902
  • 15
  • 72
  • 97