简体   繁体   中英

bokeh, change data in callback does not change original python data

I am working on a tool for manual classification which changes the property of certain dot(color in my case) chosen in a scatter plot by bokeh. I changed the source data in callback by s.data = d2 and s.change.emit() but both failed. I thought such operation will change source.data, but when I print source.data, actually nothing happens. The dots' color in the plot changes as expected though. Here is my related code:

DF = pd.read_csv(csv_path)
s = ColumnDataSource(DF_file)
p = figure(plot_width=500, plot_height=500, tooltips=TOOLTIPS,tools="lasso_select, tap", title="manual classification")
circles = p.circle('x', 'y', color='color', size=10, source=s, line_alpha=0.6,fill_alpha=0.6)
s.callback = CustomJS(args=dict(s1=s), code="""
    var inds = cb_obj.selected.indices;
    var d1 = s1.data;

    for (var i = 0; i < inds.length; i++) 
    {d1['color'][inds[i]] = 'green';} 

    s1.change.emit();
""")

Both print(s.data) and the csv file saved from s.to_csv(xxx) shows no change to the original input data. Also, I wonder how does callback work to change the plot's data while leave the data in python unchanged when the data in python is the data passed to it in args=(s1=s) .

I have searched for some possible methods and found this answer in https://discourse.bokeh.org/t/getting-selected-glyph-data-properties-via-customjs/4311/5?u=1113

when the Bokeh JS object is instantiated it uses the Python objects as sources for data but then is essentially disconnected from them - so updates to the JS model are not propagated back to their Python parents.

While the discussion in this webpage also proposed a workaround using IPython.notebook.kernel.execute to create or overwrite a variable in the Python. It can only be used in a notebook frontend(I found this workaround only works when use output_notebook() in the code).

Then here is my new code to change the original data in python:

s.callback = CustomJS(args=dict(s1=s1), code="""
    var inds = s1.selected.indices;
    var d1 = s1.data;

    for (var i = 0; i < inds.length; i++) 
    {
    d1['color'][inds[i]] = 'red';
    var index = inds[i];
    var command = "s1.data['color'][" + index + "] = red";
    var kernel = IPython.notebook.kernel;
    kernel.execute(command);
    } 

    s1.change.emit();;
""")

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM