使用multi启用Bokeh中的行

2024-06-28 18:59:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我读出了一些地点的时间和湿度数据。为了探索和分发数据,我使用Python(通过jupyter笔记本)和Bokeh。
为了简化数据探索,我希望能够启用和禁用一些位置的时间和湿度数据的I read out logger。为了探索和分发数据,我使用Python(通过jupyter笔记本)和Bokeh。
为了简化数据探索,我希望能够启用和禁用位置图(以及将来的湿度和/或温度)。为此,我想使用multiselect。在

我已经根据this post选择了多个行,但是当我尝试它时,它选择了第一个n的位置,而不是我选择的那些。在

进口

import numpy as np
import itertools
from collections import OrderedDict

from bokeh.io import push_notebook, show, output_notebook, output_file
from bokeh.layouts import row
from bokeh.palettes import Set1_6
from bokeh.plotting import figure as bf
from bokeh.models import MultiSelect, CustomJS, Range1d, LinearAxis, ColumnDataSource
from bokeh.resources import CDN
output_notebook()

辅助函数

一个函数生成示例数据

^{pr2}$

另一个函数生成javascript代码,使行可见或不可见。我试过几种方法,但没有一种能给出正确的结果。我还添加了日志以查看发生了什么以及触发了哪些if-else子句。在

def generate_selector_code(locations):
    for index, location in enumerate(locations):
        res_str = """    if (%(index)i in multiselect.attributes.value) {
        %(loc)s_t.visible = true;
        %(loc)s_rh.visible = true;
        console.log('enabling0 %(loc)s' );
    } else {
        %(loc)s_t.visible = false;
        %(loc)s_rh.visible = false;
        console.log('disabling0 %(loc)s' );
    }
    if ('%(index)i' in multiselect.attributes.value) {
        %(loc)s_t.visible = true;
        %(loc)s_rh.visible = true;
        console.log('enabling1 %(loc)s' );
    } else {
        %(loc)s_t.visible = false;
        %(loc)s_rh.visible = false;
        console.log('disabling1 %(loc)s' );
    }
    if ('%(loc)s' in multiselect.attributes.value) {
        %(loc)s_t.visible = true;
        %(loc)s_rh.visible = true;
        console.log('enabling2 %(loc)s' );
    } else {
        %(loc)s_t.visible = false;
        %(loc)s_rh.visible = false;
        console.log('disabling2 %(loc)s' );
    }
    """%({"index": index, "loc": location})
# other method's I've tested but which result into an error which states that Object does not have an attribute includes
#     if (multiselect.attributes.value.includes('%(index)i')) {
#         %(loc)s_t.visible = true;
#         %(loc)s_rh.visible = true;
#         console.log('enabling3 %(loc)s' );
#     } else {
#         %(loc)s_t.visible = false;
#         %(loc)s_rh.visible = false;
#         console.log('disabling3 %(loc)s' );
#     }
#     if (multiselect.attributes.value.includes('%(loc)s')) {
#         %(loc)s_t.visible = true;
#         %(loc)s_rh.visible = true;
#         console.log('enabling4 %(loc)s' );
#     } else {
#         %(loc)s_t.visible = false;
#         %(loc)s_rh.visible = false;
#         console.log('disabling4 %(loc)s' );
#     }

        yield res_str

设置绘图

生成示例数据并选择要使用的工具

locations = ["loc_one", "loc_two", "loc_three"]
x = np.linspace(0, 4 * np.pi, 20)
data_per_loc = OrderedDict()
for i, loc in enumerate(locations):
    data_per_loc[loc] = generate_example_data(x, i)

tools="pan,box_zoom,reset,resize,save,crosshair,hover,xbox_zoom, wheel_zoom"

生成绘图

执行实际绘图生成的函数。它创建实际的Bokeh图形并连接javascript代码来启用或禁用不同的行

def generate_plot(data_per_loc):
    palet = itertools.cycle(Set1_6)
    p = bf(title="test", plot_height=500, plot_width=1000, tools=tools, y_range=(17, 27), 
       toolbar_location="above")
    p.xaxis.axis_label = "x"

    p.yaxis.axis_label = "Temperature [°C]"
    p.extra_y_ranges = {"humidity": Range1d(start=30, end=80)}
    p.add_layout(LinearAxis(y_range_name="humidity", axis_label="Relative Humidity [%Rh]"), 'right')

    plot_locations = OrderedDict()
    for location, datadict in data_per_loc.items():
        colour = next(palet)
        source = ColumnDataSource(datadict)
        t = p.line(x='x', y='t', color=colour, source=source, legend=location)
        rh = p.line(x='x', y='rh', source=source, color=colour,
               legend=location, y_range_name='humidity',
               line_dash="dashed", )
        plot_locations.update({location+"_t": t, location+"_rh": rh})

    code = "console.log('value: ' + multiselect.attributes.value);\n " + "console.log('value_type: ' + Object.prototype.toString.call(multiselect.attributes.value).slice(8, -1));\n " +             "console.log('options: ' + multiselect.attributes.options);\n " + "".join(generate_selector_code(data_per_loc.keys()))
    return p, code, plot_locations

生成的代码如下所示:

"console.log('value: ' + multiselect.attributes.value);
 console.log('value_type: ' + Object.prototype.toString.call(multiselect.attributes.value).slice(8, -1));
 console.log('options: ' + multiselect.attributes.options);
 if (0 in multiselect.attributes.value) {
    loc_one_t.visible = true;
    loc_one_rh.visible = true;
    console.log('enabling0 loc_one' );
} else {
    loc_one_t.visible = false;
    loc_one_rh.visible = false;
    console.log('disabling0 loc_one' );
}
if ('0' in multiselect.attributes.value) {
    loc_one_t.visible = true;
    loc_one_rh.visible = true;
    console.log('enabling1 loc_one' );
} else {
    loc_one_t.visible = false;
    loc_one_rh.visible = false;
    console.log('disabling1 loc_one' );
}
if ('loc_one' in multiselect.attributes.value) {
    loc_one_t.visible = true;
    loc_one_rh.visible = true;
    console.log('enabling2 loc_one' );
} else {
    loc_one_t.visible = false;
    loc_one_rh.visible = false;
    console.log('disabling2 loc_one' );
}
    if (1 in multiselect.attributes.value) {
    loc_two_t.visible = true;
    loc_two_rh.visible = true;
    console.log('enabling0 loc_two' );
} else {
    loc_two_t.visible = false;
    loc_two_rh.visible = false;
    console.log('disabling0 loc_two' );
}
if ('1' in multiselect.attributes.value) {
    loc_two_t.visible = true;
    loc_two_rh.visible = true;
    console.log('enabling1 loc_two' );
} else {
    loc_two_t.visible = false;
    loc_two_rh.visible = false;
    console.log('disabling1 loc_two' );
}
if ('loc_two' in multiselect.attributes.value) {
    loc_two_t.visible = true;
    loc_two_rh.visible = true;
    console.log('enabling2 loc_two' );
} else {
    loc_two_t.visible = false;
    loc_two_rh.visible = false;
    console.log('disabling2 loc_two' );
}
    if (2 in multiselect.attributes.value) {
    loc_three_t.visible = true;
    loc_three_rh.visible = true;
    console.log('enabling0 loc_three' );
} else {
    loc_three_t.visible = false;
    loc_three_rh.visible = false;
    console.log('disabling0 loc_three' );
}
if ('2' in multiselect.attributes.value) {
    loc_three_t.visible = true;
    loc_three_rh.visible = true;
    console.log('enabling1 loc_three' );
} else {
    loc_three_t.visible = false;
    loc_three_rh.visible = false;
    console.log('disabling1 loc_three' );
}
if ('loc_three' in multiselect.attributes.value) {
    loc_three_t.visible = true;
    loc_three_rh.visible = true;
    console.log('enabling2 loc_three' );
} else {
    loc_three_t.visible = false;
    loc_three_rh.visible = false;
    console.log('disabling2 loc_three' );
}
"

第一次尝试把它结合起来

output_file("c:\html\multiselect_loc.html")
p, code, plot_locations = generate_plot(data_per_loc)

ms_options = locations
ms_value = locations

callback = CustomJS(code=code, args={})
multiselect = MultiSelect(title="Location:", options=ms_options, value=ms_value, callback=callback)
callback.args = dict(**plot_locations, multiselect=multiselect)


layout = row(p, multiselect)
show(layout)

第二次尝试把它结合起来

我认为javascript可能在字符串作为值方面有问题,所以我尝试使用int作为multiselect的值

output_file("c:\html\multiselect_val.html")
p, code, plot_locations = generate_plot(data_per_loc) 

ms_options = [(str(i), v) for i , v in enumerate(locations)]
ms_value = [str(i) for i in range(len(locations))]

callback = CustomJS(code=code, args={})
multiselect = MultiSelect(title="Location:", options=ms_options value=ms_value, callback=callback)
callback.args = dict(**plot_locations, multiselect=multiselect)


layout = row(p, multiselect)
show(layout)

结果

博克毫无疑问地画出了这些线条,但选择的动作很奇怪。它没有显示我想要的位置,而是用前两种选择方法给出了第一条n行,而没有给出第三种选择方法

javascript控制台返回如下内容:

value: loc_two
value_type: Array
options: loc_one,loc_two,loc_three
enabling0 loc_one
enabling1 loc_one
disabling2 loc_one
disabling0 loc_two
disabling1 loc_two
disabling2 loc_two
disabling0 loc_three
disabling1 loc_three
disabling2 loc_three
value: loc_two,loc_three
value_type: Array
options: loc_one,loc_two,loc_three
enabling0 loc_one
enabling1 loc_one
disabling2 loc_one
enabling0 loc_two
enabling1 loc_two
disabling2 loc_two
disabling0 loc_three
disabling1 loc_three
disabling2 loc_three

the results set in a table

我已经在github repo my github repo上添加了所有示例代码,以及javascript控制台输出。所有这些都通过IE11(公司限制)进行了测试。在


Tags: inlogfalsetrueifvalueoneloc
2条回答

另一种方法是使用CustomJS.from_coffeescript(),并将代码从JS更改为CoffeeScript

res_str = """\
if '%(loc)s' in multiselect.attributes.value
    %(loc)s_t.visible = true
    %(loc)s_rh.visible = true
    console.log 'enabling %(loc)s'
} else {
    %(loc)s_t.visible = false
    %(loc)s_rh.visible = false
    console.log 'disabling %(loc)s'
}
"""%({"index": index, "loc": location})

我已经找到了罪魁祸首,事实上是检查数组的键(0到len-1)而不是值

    res_str = """\
if (multiselect.attributes.value.indexOf('%(loc)s')>-1) {
    %(loc)s_t.visible = true;
    %(loc)s_rh.visible = true;
    console.log('enabling5 %(loc)s' );
} else {
    %(loc)s_t.visible = false;
    %(loc)s_rh.visible = false;
    console.log('disabling5 %(loc)s' );
}
"""%({"index": index, "loc": location})

def generate_selector_code(locations):中的测试是否正确

我在查看the bokeh example中使用CustomJS.from_coffeescript()的代码并浏览CoffeeScript documentation时注意到了这一点

^{pr2}$

相关问题 更多 >