How to update a source in a JavaScript Callback of

2019-08-23 02:40发布

I am adapting this answer for my case, where I want an interactive, standalone graph where the slider selects which column of the data to plot in a bar chart. (Standalone is crucial, I cannot run a Bokeh server, thus the need for JavaScript callbacks.)

The data is a rectangle of floats with 100 rows in each of the 38 columns, which all have string labels like '40' etc. (This is how pandas .read_csv() handles numerics in the header by default.) Here is a sample from the top left corner (3x3, plus the row and column labels):

        # ,        40,        41,        42,
   1.00000,   1.00000,   0.99287,   0.98489,
   2.00000,   1.00000,   0.99348,   0.98626,
   3.00000,   1.00000,   0.99433,   0.98922,

The code below produces the graph for the first column but does not update the graph upon moving the slider.

By poking at it, I suspect the issue is with the JavaScript code, though ColumnDataSource remains a bit mysterious to me. (A more straightforward dictionary of numeric column labels to lists of the numbers in the column does not work as datasource_available, though corresponds to the linked answer's use case.)

datadf = pd.read_csv('male_survival_by_pctile.csv')
datadf.set_index('# ',inplace=True)
years = range(40,77)
data = {}
data_available = {}

for year in years:
    data[year] = {'top':datadf[str(year)],'x':range(1,101)}
data_available = ColumnDataSource.from_df(datadf)

from bokeh.core.properties import field
from bokeh.io import curdoc, output_notebook, show
from bokeh.layouts import layout, column
from bokeh.models import (ColumnDataSource, HoverTool, SingleIntervalTicker,
                          Slider, Button, Label, CustomJS)
from bokeh.plotting import figure

output_notebook()

source_visible = ColumnDataSource(data=dict(x=range(1,101),top=data_available[str(years[0])]))
source_available = ColumnDataSource(data=data_available)

plot = figure(output_backend="webgl")
plot.xaxis.ticker = SingleIntervalTicker(interval=.01)
plot.xaxis.axis_label = "Income percentile"
plot.yaxis.ticker = SingleIntervalTicker(interval=.05)
plot.yaxis.axis_label = "Survival rate"

label = Label(x=1.1, y=18, text=str(years[0]), text_font_size='70pt', text_color='#eeeeee')
plot.add_layout(label)

plot.vbar(top='top',x='x',width=1,source=source_visible)

slider = Slider(start=years[0], end=years[-1], value=years[0], step=1, title="Age")

slider.callback = CustomJS(
    args=dict(source_visible=source_visible,
              source_available=source_available), code="""
        var selected_function = cb_obj.get('value').toString();
        // Get the data from the data sources
        var data_visible = source_visible.get('data');
        var data_available = source_available.get('data');
        // Change bar height to the selected value
        data_visible.top = data_available[selected_function];
        // Update the plot
        source_visible.trigger('change');
    """)

layout = column(slider, plot)

show(layout)

1条回答
可以哭但决不认输i
2楼-- · 2019-08-23 02:48

The issue is in the CustomJS code as you suspected. There are two things that need to be fixed.

  1. Bokeh has deprecated get() and set() methods and replaced them by getv() or setv(). However, the preferred way of accessing or modifying model properties is through usual JavaScript attributes, e.g., source_visible.data.

  2. Bokeh has deprecated trigger('change') and replaced it by change.emit().

The fixed CustomJS code:

slider.callback = CustomJS(
    args=dict(source_visible=source_visible,
              source_available=source_available), code="""
        var selected_function = cb_obj.value.toString();
        // Get the data from the data sources
        var data_visible = source_visible.data;
        var data_available = source_available.data;
        // Change bar height to the selected value
        data_visible.top = data_available[selected_function];
        // Update the plot
        source_visible.change.emit();
    """)

JavaScript errors and warnings are seen in the browser's console. Here are instructions for opening the console in different browsers.

查看更多
登录 后发表回答