1

I have a simple ColumnDataSource of multiple columns, each column representing a different day of a simulation and each row representing the number of entities with status a, b, c,.. etc. I'd like to be able to scrub through the days (columns) with a slider.

I've taken a look at 1, 2, and the Bokeh docs for information but I haven't been able to successfully get it working. I have the following code (minimal):

from bokeh.plotting import figure
from bokeh.layouts import column, widgetbox
from bokeh.models import CustomJS, Slider, ColumnDataSource, ranges
from bokeh.io import output_file, show

output_file("barplot.html")
sim_time=4

data = {'x': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
        '0': [2860.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '1': [2860.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '2': [0.0, 2860.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '3': [0.0, 2860.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]}

source = ColumnDataSource(data)

barplot = figure(plot_width=800, plot_height=600, tools='pan', x_axis_label='Status', x_range=source.data['x'], y_range=ranges.Range1d(start=0, end=3000))
barplot.vbar(source=source, x='x', top='0', width=0.6)

callback = CustomJS(args={'source':source}, code="""
    console.log(' changed selected time', cb_obj.value);
    var data = source.data;
    data['0'] = data[cb_obj.value];
    source.change.emit()
""")

time_slider = Slider(start=0, end=sim_time-1, value=1, step=1, callback=callback)
callback.args["time"] = time_slider

show(column(barplot, time_slider))

i.e. I'm not able to scrub through the columns using a slider.

What am I doing wrong?

Cheers

1 Answer 1

1

Try this:

data = {'x': ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'],
        'y': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '0': [0.0, 0.0, 0.0, 0.0, 500.0, 0.0, 0.0, 0.0],
        '1': [0.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '2': [0.0, 0.0, 1000.0, 0.0, 0.0, 0.0, 0.0, 0.0],
        '3': [0.0, 0.0, 0.0, 1000.0, 0.0, 0.0, 0.0, 0.0]}

source = ColumnDataSource(data)

barplot = figure(plot_width=800, plot_height=600, tools='pan',
                 x_axis_label='Status', x_range=source.data['x'],
                 y_range=ranges.Range1d(start=0, end=3000))
barplot.vbar(source=source, x='x', top='y', width=0.6)

callback = CustomJS(args=dict(source=source), code="""
    console.log(' changed selected time', cb_obj.value);
    var data = source.data;
    data['y'] = data[cb_obj.value];
    source.change.emit()
""")

time_slider = Slider(start=0, end=sim_time-1, value=0, step=1, callback=callback)
callback.args["time"] = time_slider    
show(column(barplot, time_slider))

There are two issues with your code. Your bars for 0 1 and 2 3 are identical. You won't see any change between choosing 2 and 3. Also, you use the 0 column for storing data. But then you overwrite the data in 0 in your JS code. Thus, the data gets lost. Consequently, switching back to 0 on the slider won't have an effect. This is why I added a new (empty) column y to your data. This is just a placeholder used for plotting holding the currently selected data.

Sign up to request clarification or add additional context in comments.

2 Comments

I appreciate the quick reply! I applied all your suggestions but the scrubbing is still not working. Upon looking at the browser console, it's telling me that source.change.emit() is throwing TypeErrors of "undefined is not an object". Any thoughts?
Solved the problem-- this functionality was broken on bokeh 0.12.5 but is fully functional on 0.12.7.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.