Bokeh: Change source data on callback

Created on 1 Jul 2016  路  3Comments  路  Source: bokeh/bokeh

As ref: http://bokeh.pydata.org/en/latest/docs/user_guide/interaction.html#customjs-with-a-python-function

My code:

df = pd.read_sql_query('select * from data', con=engine)

source = ColumnDataSource(df[df.origin==1])

def callback(source=source, window=None):
    source.data = df[df.origin==cb_obj.get('value')].to_dict()
    source.trigger('change')

slider = Slider(start=1, end=8, value=1, step=1, title="Origin",
                callback=CustomJS.from_py_func(callback))

fig = figure(responsive=True)
fig.circle(source.data['x'], source.data['y'])

layout = column(slider, fig)

show(layout)

Changing the slider does nothing.
Why is this, and what am I supposed to do to explicitly assign new data interactively?

referred discussion

Most helpful comment

Hey Rornor, Bryan,

I ran into the same issue and found a sort of hacky solution.

You can also create a dummy/default data source & pass multiple data sources to the callback. Then, iterate through the dummy/default data source in JS deleting all elements of the object and replace it with another data source. I did this with a Selection widget though, not a slider.

Refer to http://stackoverflow.com/questions/43231896/changing-source-of-plot-in-bokeh-with-a-callback

Example:

callback = CustomJS(args={
  'source1': source_dummy, 
  'source2': source_selectionA,
  'source3': source_selectionB,
  'source4': source_selectionC}, code="""

    var data1 = source1.data;
    var data2 = source2.data;
    var data3 = source3.data;
    var data4 = source4.data;
    var f = cb_obj.value;

    if (f == 'A') {
      for (var e in data1) delete data1[e];  //clears the dummy datasource

      data1['x'] = data2['x'];
      data1['y'] = data2['y'];
    }

    if (f == 'B') {
      for (var e in data1) delete data1[e];

      data1['x'] = data3['x']
      data1['y'] = data3['y'];
    }

    if (f == 'C') {
      for (var e in data1) delete data1[e];

      data1['x'] = data4['x']
      data1['y'] = data4['y'];
    }

    source1.trigger('change');
""")

select = Select(title='Choose', value='A', options=['A','B','C'])
select.js_on_change('value', callback)

All 3 comments

Sorry, I posted a response in error.

What you have cannot work, CustomJS callbacks _only every execute JavaScript, and cannot execute "real" python_

the from_py_func is a convenience that "translates" python to javascript, but only very simple python that does not involve any other libraries, etc, can work in this way. Real calls to libraries like pandas _cannot_ work, because they require real python, and the browser has no way to execute python. Only javascript.

If you need to run real python on your callbacks (e.g, pandas, scikits, etc) you will have to use a bokeh server app, like the ones on https://demo.bokehplots.com

Finally, please use the mailing list for general support questions like this as we reserver the tracke for bug reports and feature requests. There are more people on the mailing list that can potentially help.

@bryevdv thanks for explanation and sorry for opening at wrong place.

While here can you be kind to replay:

  1. In Python callback, can I change inline source.data (assuming I get dict) and expect bokeh graph to update? For example source.data = some_dict_with_same_scheme. Or do I have to set x, y variables as lists with new values, explicitly.
  2. Can I somehow debug this callback or see the data (like console.log() in JS callback)

Hey Rornor, Bryan,

I ran into the same issue and found a sort of hacky solution.

You can also create a dummy/default data source & pass multiple data sources to the callback. Then, iterate through the dummy/default data source in JS deleting all elements of the object and replace it with another data source. I did this with a Selection widget though, not a slider.

Refer to http://stackoverflow.com/questions/43231896/changing-source-of-plot-in-bokeh-with-a-callback

Example:

callback = CustomJS(args={
  'source1': source_dummy, 
  'source2': source_selectionA,
  'source3': source_selectionB,
  'source4': source_selectionC}, code="""

    var data1 = source1.data;
    var data2 = source2.data;
    var data3 = source3.data;
    var data4 = source4.data;
    var f = cb_obj.value;

    if (f == 'A') {
      for (var e in data1) delete data1[e];  //clears the dummy datasource

      data1['x'] = data2['x'];
      data1['y'] = data2['y'];
    }

    if (f == 'B') {
      for (var e in data1) delete data1[e];

      data1['x'] = data3['x']
      data1['y'] = data3['y'];
    }

    if (f == 'C') {
      for (var e in data1) delete data1[e];

      data1['x'] = data4['x']
      data1['y'] = data4['y'];
    }

    source1.trigger('change');
""")

select = Select(title='Choose', value='A', options=['A','B','C'])
select.js_on_change('value', callback)
Was this page helpful?
0 / 5 - 0 ratings