简体   繁体   English

使用 customjs 回调更改时,Bokeh-Source 未正确更新 plot 上的所有行

[英]Bokeh-Source not updating for all lines on plot correctly when changed with customjs callback

I have a dataframe that is concentration over runs for 22 elements.我有一个 dataframe ,它集中了 22 个元素的运行。 It's structured like this它的结构是这样的

      run           9Be       45Sc    .....
3/24/16 Run A      0.9280     nan
3/24/16 Run B      1.1052     0.4904
4/6/16 Run A       0.490      0.3374

For each element I need to plot the concentration over runs as well as the mean and standard deviations (as solid lines) for that element.对于每个元素,我需要 plot 运行浓度以及该元素的平均值和标准偏差(如实线)。 I want to make a bokeh plot where I can select an element in the table and the plot will update with that element's data.我想制作散景 plot ,我可以在其中 select 是表格中的一个元素,并且 plot 将使用该元素的数据进行更新。 Code is below代码如下

os.chdir(r'')


low=pd.read_excel(r"", sheet_name="QC LOW", skiprows=5, usecols=range(0,34))
low["run"]=low["run"].astype(str)
low.loc[~(low["run"].str.contains("A")) & ~(low["run"].str.contains("B")),"run"]=pd.to_datetime(low.loc[(~low["run"].str.contains("A")) & (~low["run"].str.contains("B")),"run"]).dt.strftime('%m/%d/%y')
cols=low.columns.tolist()
cols=cols[2:]

select = Select(title="Option:", value="9Be", options=cols)

source=ColumnDataSource(data=low)

#Using 9Be as default. Will be changed when updated
mean=source.data['9Be'].mean()
plus_three_sigma=mean+(source.data['9Be'].std()*3)
minus_three_sigma=mean-(source.data['9Be'].std()*3)
plus_two_sigma=mean+(source.data['9Be'].std()*2)
minus_two_sigma=mean-(source.data['9Be'].std()*2)

tips=[("Run", "@Run"),("Concentration", "$y")]
p = figure(plot_width=1300, plot_height=800, x_range=source.data["run"], tooltips=tips, title="QC Low", x_axis_label="Run ID",y_axis_label="Concentration ng/mL")
p.line(x=source.data["run"], y=mean, line_width=1, color="black")
p.line(x=source.data["run"], y=plus_three_sigma, line_width=1, color="red")
p.line(x=source.data["run"], y=minus_three_sigma, line_width=1, color="red")
p.line(x=source.data["run"], y=minus_two_sigma, line_width=1, color="green",line_dash="dashed")
p.line(x=source.data["run"], y=plus_two_sigma, line_width=1, color="green",line_dash="dashed")
pc=p.circle(x='run', y="9Be",source=source)
p.xaxis.major_label_orientation = 1.2

callback = CustomJS(args=dict(source=source), code="""
    var data=source.data;
    data['9Be'] = data[cb_obj.value];
    source.change.emit();
""")

output_file("output.html")


select.js_on_change('value', callback)

show(row(select,p))

Currently the scatterplot updates correctly when selecting elements...most of the time (it does not always update. For example if I select an element and then try to select 9Be again).目前散点图在选择元素时会正确更新......大多数时候(它并不总是更新。例如,如果我 select 一个元素然后尝试 select 9Be 再次)。 But my main issue is that the means and standard deviations are not being updated even though the source should be changing?但我的主要问题是,即使来源应该改变,手段和标准差也没有更新?

You're using a static HTML file created with show , but you need to run Python code when the current item changes.您正在使用使用show创建的 static HTML 文件,但是当当前项目更改时,您需要运行 Python 代码。 Either you have to run the Python code that computes the mean and other parameters for all columns in advance and store them to be used later in the CustomJS.code , or you have to use bokeh serve to be able to run Python callbacks in response to some user action.您必须运行 Python 代码,该代码预先计算所有列的平均值和其他参数并将它们存储以供稍后在CustomJS.code中使用,或者您必须使用bokeh serve才能运行 Python 回调以响应一些用户操作。

Another issue with your code is that you change the data in CustomJS.code .您的代码的另一个问题是您更改了CustomJS.code中的数据。 Don't do that - you're just overwriting the 9Be values, losing them entirely.不要那样做——你只是覆盖了9Be值,完全失去了它们。 Instead, save each renderer (the value returned from p.line , p.circle , etc.), pass the renderers to CustomJS.args (just as with source , you will have to give them some names), and update the relevant field instead of updating the data.相反,保存每个渲染器(从p.linep.circle等返回的值),将渲染器传递给CustomJS.args (就像使用source一样,您必须给它们一些名称),并更新相关字段而不是更新数据。 It should look something like this in CustomJS.code :它在CustomJS.code中应该看起来像这样:

pc.glyph.y = {field: cb_obj.value};

The {field: ...} part is needed for BokehJS - it's created by Boken on the Python side automatically for you, but you have to apply it manually in CustomJS.code . BokehJS 需要{field: ...}部分 - 它由 Boken 在 Python 端自动为您创建,但您必须在CustomJS.code中手动应用它。 For static values, like a precomputed mean, it would be something like:对于 static 值,如预先计算的平均值,它将类似于:

mean_renderer.glyph.y = {value: current_mean};

How you store current_mean is up to you.如何存储current_mean取决于您。 You can store all precomputed means in eg another data source and just change the column name with {field: ...} instead of changing the value with {value: ...} .您可以将所有预先计算的方法存储在另一个数据源中,只需使用{field: ...}更改列名,而不是使用{value: ...}更改值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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