okurniawan
okurniawan

Reputation: 13

Plotting different column using CustomJS callbacks with slider

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

Upvotes: 1

Views: 278

Answers (1)

mc51
mc51

Reputation: 2287

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.

Upvotes: 1

Related Questions