繁体   English   中英

如何在 Bokeh (Python) 中编写自定义 JS 回调?

[英]How to write custom JS callback in Bokeh (Python)?

我尝试用 Bokeh 构建一个动态图表,我对 JavaScript 部分很感兴趣,用自定义 JS 回调的措辞。 我确切地说我绝对不熟悉 JavaScript。

这是我的 dataframe:

 num_tra num_ts Item annee  valeur TRA_label TS_label     TRA   TS   Sensi     Cumul
        1   1    PVFP   10  62     0 bps        0 bps     0     0    Sensi     62
        1   1    PVFP   20  28     0 bps        0 bps     0     0    Sensi     90
        1   1    PVFP   30  87     0 bps        0 bps     0     0    Sensi     177
        1   2    PVFP   10  25     0 bps        - 15 bps  0     -15  Sensi     25
        1   2    PVFP   20  95     0 bps        - 15 bps  0     -15  Sensi     120
        1   2    PVFP   30  95     0 bps        - 15 bps  0     -15  Sensi     215
        2   1    PVFP   10  49     - 10 bps     0 bps     -10   0    Sensi     49
        2   1    PVFP   20  17     - 10 bps     0 bps     -10   0    Sensi     66
        2   1    PVFP   30  98     - 10 bps     0 bps     -10   0    Sensi     164
        2   2    PVFP   10  83     - 10 bps     - 15 bps  -10   -15  Sensi     83
        2   2    PVFP   20  58     - 10 bps     - 15 bps  -10   -15  Sensi     141
        2   2    PVFP   30  52     - 10 bps     - 15 bps  -10   -15  Sensi     193
        1   1    PVFP   10  44     0 bps        0 bps     0     0    Central   44
        1   1    PVFP   20  60     0 bps        0 bps     0     0    Central   104
        1   1    PVFP   30  97     0 bps        0 bps     0     0    Central   201
        1   2    PVFP   10  82     0 bps        - 15 bps  0     -15  Central   82
        1   2    PVFP   20  88     0 bps        - 15 bps  0     -15  Central   170
        1   2    PVFP   30  38     0 bps        - 15 bps  0     -15  Central   208
        2   1    PVFP   10  58     - 10 bps     0 bps     -10   0    Central   58
        2   1    PVFP   20  30     - 10 bps     0 bps     -10   0    Central   88
        2   1    PVFP   30  69     - 10 bps     0 bps     -10   0    Central   157
        2   2    PVFP   10  2      - 10 bps     - 15 bps  -10   -15  Central   2
        2   2    PVFP   20  62     - 10 bps     - 15 bps  -10   -15  Central   64
        2   2    PVFP   30  69     - 10 bps     - 15 bps  -10   -15  Central   133

我正在寻找的是一个基于变量 num_tra 和 num_ts 的值的带有两个滑块(slider_TRA 和 slider_TS)的图表。 最后,我想根据两个滑块的值更新 plot 的来源。

基于 Bokeh 文档示例,我尝试构建以下代码,但不知道如何处理 JS 部分:

import numpy as np
import pandas as pd
from bokeh.models import ColumnDataSource, CustomJS, Slider
from bokeh.layouts import column, row
from bokeh.plotting import ColumnDataSource, figure, output_file, show

central=pvfp.loc[pvfp.Sensi=="Central"]
sensi=pvfp.loc[pvfp.Sensi=="Sensi"]

source1 = ColumnDataSource(central)
source2 = ColumnDataSource(sensi)

plot = figure(plot_width=400, plot_height=400)
plot.line('annee', 'valeur', source=source1)
plot.line('annee', 'valeur', source=source2)

slider_TRA = Slider(start=1, end=2, value=1, step=1, title="Sensi TRA")
slider_TS = Slider(start=1, end=2, value=1, step=1, title="Sensi TS")

callback = CustomJS(

    args=dict(source1=source1,source2=source2, slider_TRA=slider_TRA,slider_TS=slider_TS),

    code="""
    const data1 = source1.data;
    const data2 = source2.data;
    const stra = slider_TRA.value;
    const sts = slider_TS.value;
    const num_tra1 = data1['num_tra']
    const num_ts1 = data1['num_ts']
    const num_tra2 = data2['num_tra']
    const num_ts2 = data2['num_ts']
    
    for ...some JS to say : 
    num_tra1=num_tra2=stra
    num_ts1=num_ts2=sts
    
    and
    
    source1=source1.loc[(source1.num_tra==num_tra1)&(source1.num_ts==num_ts1)]
    source2=source2.loc[(source2.num_tra==num_tra2)&(source2.num_ts==num_ts2)]
    
    source1.change.emit();
    source2.change.emit();
    """
)

slider_TRA.js_on_change('value', callback)
slider_TS.js_on_change('value',callback)

layout = row(
    plot,
    column(slider_TRA, slider_TS),
)

show(layout)

如上所述,我对JS不熟悉,我正在寻找可以帮助我的人。 如果您有任何想法或建议,将不胜感激。

此解决方案适用于 Bokeh v2.3.0。 您需要将完整的数据传递给回调 function 并根据 slider 值进行过滤。 但是您不能将生成的过滤数据分配给原始数据,因为这样会丢失信息。 所以你应该将过滤后的数据分配给相应字形的data_source object。 此外,两条线的起始数据应根据初始 slider 位置进行过滤。

import os
import pandas as pd
from bokeh.models import ColumnDataSource, CustomJS, Slider, BooleanFilter, CDSView
from bokeh.layouts import column, row
from bokeh.plotting import figure, show

pvfp = pd.read_csv(os.path.join(os.path.dirname(__file__), 'data', 'data.csv'), sep = ",")

central = pvfp.loc[pvfp.Sensi=="Central"]
sensi = pvfp.loc[pvfp.Sensi=="Sensi"]

min_tra_central = central['num_tra'].min()
max_tra_central = central['num_tra'].max()
min_ts_central = central['num_ts'].min()
max_ts_central = central['num_ts'].max()

min_tra_sensi = sensi['num_tra'].min()
max_tra_sensi = sensi['num_tra'].max()
min_ts_sensi = sensi['num_ts'].min()
max_ts_sensi = sensi['num_ts'].max()

start_tra = min(min_tra_central, min_tra_sensi)
start_ts = min(min_ts_central, min_ts_sensi)

end_tra = max(max_tra_central, max_tra_sensi)
end_ts = max(max_ts_central, max_ts_sensi)

slider_TRA = Slider(start = start_tra, end = end_tra, value=start_tra, step=1, title="Sensi TRA", show_value = False)
slider_TS = Slider(start = start_ts, end = end_ts, value=start_ts, step=1, title="Sensi TS", show_value = False)

##########################################################################

plot = figure(plot_width=400, plot_height=400)

source_central = ColumnDataSource(central)
source_sensi = ColumnDataSource(sensi)

source_start_central = central.loc[(central['num_tra'] == start_tra) & (central['num_ts'] == start_ts)]
source_start_sensi = sensi.loc[(sensi['num_tra'] == start_tra) & (sensi['num_ts'] == start_ts)]

line_central = plot.line('annee', 'valeur', color = 'red', source=source_start_central)
line_sensi = plot.line('annee', 'valeur', color = 'blue', source=source_start_sensi)

##########################################################################

callback = CustomJS(
    args=dict(source_central=source_central, source_sensi=source_sensi, line_central=line_central, line_sensi=line_sensi, slider_TRA=slider_TRA, slider_TS=slider_TS),
    code="""
    const data_central = source_central.data;
    const data_sensi = source_sensi.data;
    const tra_value = slider_TRA.value;
    const ts_value = slider_TS.value;
    
    var new_central_y = []
    var new_sensi_y = []
    
    for (var i=0; i<data_central['num_tra'].length; i++) {
        if(data_central['num_tra'][i] == tra_value && data_central['num_ts'][i] == ts_value) {
            new_central_y.push(data_central['valeur'][i])
        }
        
        if(data_sensi['num_tra'][i] == tra_value && data_sensi['num_ts'][i] == ts_value) {
            new_sensi_y.push(data_sensi['valeur'][i])
        }
    }
    
    line_central.data_source.data['valeur'] = new_central_y
    line_sensi.data_source.data['valeur'] = new_sensi_y

    line_central.data_source.change.emit();
    line_sensi.data_source.change.emit();
    """
)

slider_TRA.js_on_change('value', callback)
slider_TS.js_on_change('value', callback)

layout = row(
    plot,
    column(slider_TRA, slider_TS),
)

show(layout)

结果: 在此处输入图像描述

暂无
暂无

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

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