Javascript 如何在Bokeh中更新多选菜单

Javascript 如何在Bokeh中更新多选菜单,javascript,bokeh,Javascript,Bokeh,我是Bokeh的新手,我尝试根据用户先前在另一个multiselect菜单中的选择更新multiselect菜单,但没有成功。没有给出错误,但根据“种类”菜单中的选择,下面代码中的“设置”菜单未更新。我可能在最后一次回调(第142-146行)时出错了,但我不知道如何修复它。想法 # Data handling import pandas as pd # Bokeh libraries from bokeh.plotting import figure, output_file, show

我是Bokeh的新手,我尝试根据用户先前在另一个multiselect菜单中的选择更新multiselect菜单,但没有成功。没有给出错误,但根据“种类”菜单中的选择,下面代码中的“设置”菜单未更新。我可能在最后一次回调(第142-146行)时出错了,但我不知道如何修复它。想法



# Data handling
import pandas as pd

# Bokeh libraries
from bokeh.plotting import figure, output_file, show
from bokeh.embed import components
from bokeh.models import Toggle, ColumnDataSource, FactorRange, Callback, CustomJS
from bokeh.models.widgets import DataTable, NumberFormatter, TableColumn, HTMLTemplateFormatter
from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models.widgets import TextInput, MultiSelect

# test data
original_data = dict(species = ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','B','C','D','E','A','A'],
length = [2, 10, 20, 40, 60, 80, 70, 50, 15, 36, 76, 74, 72, 44, 36, 18, 40, 64, 40, 64, 40, 30, 120],
weight = [2, 100, 150, 200, 420, 700, 600, 300, 200, 200, 620, 610, 601, 610, 601, 80, 205, 80, 800, 700, 240, 160, 800],
set_number = ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '3', '4', '1', '5', '1'],
sex_id = [2, 0, 0, 0, 2, 1, 1, 0, 2, 1, 1, 1, 0, 1, 1, 0, 2, 1, 1, 2, 1, 0, 2])

original_data = pd.DataFrame(original_data)
original_data['color'] = 'black'

original_source = ColumnDataSource(original_data)

# Empty source so the plot is empty before the data is selected
source = ColumnDataSource(dict(species = [], set_number = [], length = [], weight = [], sex_id = [], color = []))

### Main plot
plot = figure(title = 'Length-weight scatterplot', x_axis_label = 'length (cm)', y_axis_label = 'weight (g)',
        tools = "pan, hover, box_zoom, reset, save", toolbar_location = "right", 
        plot_width = 450, plot_height = 450)

plot.circle(x = 'length', y = 'weight', color = 'color', fill_alpha = 1, source = source, line_width = 2)

# Select species
available_species = list(set(original_data['species']))
available_species.sort()

species_callback = CustomJS(args = {'source': source, 'original_source': original_source},
code = """
var data = original_source.data;
var source_data = source.data;

var species_data = data['species'];
var length_data = data['length'];
var weight_data = data['weight'];
var sex_id_data = data['sex_id'];
var set_number_data = data['set_number'];
var color_data = data['color'];
var selected_species = cb_obj.value;

var source_length = source_data['length'];
source_length.length = 0;

var source_weight = source_data['weight'];
source_weight.length = 0;

var source_sex_id = source_data['sex_id'];
source_sex_id.length = 0;

var source_species = source_data['species'];
source_species.length = 0;

var source_set_number = source_data['set_number'];
source_set_number.length = 0;

var source_color = source_data['color'];
source_color.length = 0;
for (var i = 0; i < length_data.length; i++) {
if (selected_species.indexOf(species_data[i]) >= 0) 
source_length.push(length_data[i]);
source_weight.push(weight_data[i]);
source_species.push(species_data[i]);
source_set_number.push(set_number_data[i]);
source_sex_id.push(sex_id_data[i]);
source_color.push(color_data[i]);
}
}
source.change.emit();
""")

multiselect_species = MultiSelect(title = 'Species:', value = [], options = available_species, width = 240)
#multiselect_species.js_on_change('value', species_callback)

# Select set (multiselect)
#available_set = list(set(map(str, original_data['set_number'])))
available_set = list(set(original_data['set_number']))
available_set.sort()

set_callback = CustomJS(args = {'source': source, 'original_source': original_source},
code = """
var data = original_source.data;
var source_data = source.data;

var species_data = data['species'];
var length_data = data['length'];
var weight_data = data['weight'];
var sex_id_data = data['sex_id'];
var set_number_data = data['set_number'];
var color_data = data['color'];
var selected_species = cb_obj.value;

var source_length = source_data['length'];
source_length.length = 0;

var source_weight = source_data['weight'];
source_weight.length = 0;

var source_sex_id = source_data['sex_id'];
source_sex_id.length = 0;

var source_species = source_data['species'];
source_species.length = 0;

var source_set_number = source_data['set_number'];
source_set_number.length = 0;

var source_color = source_data['color'];
source_color.length = 0;

 for (var i = 0; i < length_data.length; i++) {
 if (selected_species.indexOf(set_number_data[i]) >= 0) {

 source_length.push(length_data[i]);
 source_weight.push(weight_data[i]);
 source_species.push(species_data[i]);
 source_set_number.push(set_number_data[i]);
 source_sex_id.push(sex_id_data[i]);
 source_color.push(color_data[i]);
 }
 }
 source.change.emit();
 """)

multiselect_set = MultiSelect(title = 'Set:', value = [], options = available_set, width = 240)
multiselect_set.js_on_change('value', set_callback)

# The sets available should be updated depending on the species chosen
multiselect_species.js_on_change('value', species_callback, CustomJS(args = dict(multiselect_set = multiselect_set,
                                                                                  available_set = available_set),
code = """
const var_set = %s
multiselect_set.options = var_set.[cb_obj.value]
multiselect_set.options = multiselect_set.options.join()
""" % available_set))

# Data table
columns = [TableColumn(field = "species", title = "common name", width = 100),
           TableColumn(field = "set_number", title = "set number", width = 100),
           TableColumn(field = "length", title = "length (cm)", width = 100),
           TableColumn(field = "weight", title = "weight (g)", width = 100),
           TableColumn(field = "sex_id", title = "sex", width = 100)]

data_table = DataTable(source = source, columns = columns, sortable = True, editable = True, width = 500, height = 450,
                        fit_columns = True)

# Set up widgets layout
widgets_layout = column(multiselect_species, multiselect_set)

# Set up figures layout
figures_layout = row(plot, data_table)

# Set up page layout
page_layout = row(widgets_layout, figures_layout)

show(page_layout)


```I

#数据处理
作为pd进口熊猫
#博克图书馆
从bokeh.plotting导入图形,输出_文件,显示
从bokeh.embed导入组件
从bokeh.models导入切换、ColumnDataSource、FactorRange、回调、CustomJS
从bokeh.models.widgets导入DataTable、NumberFormatter、TableColumn、HTMLTemplateFormatter
从bokeh.io导入curdoc
从bokeh.layouts导入行、列
从bokeh.models.widgets导入文本输入,MultiSelect
#测试数据
原始数据=dict(物种=['A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'A'、'B'、'C'、'D'、'E'、'A'、'A'],
长度=[2,10,20,40,60,80,70,50,15,36,76,74,72,44,36,18,40,64,40,64,64,40,30,120],
重量=[2100、150、200、420、700、600、300、200、200、620、610、601、610、601、80、205、80、800、700、240、160、800],
集合编号=['1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','2','3','4','1','5','1'],
sex_id=[2,0,0,2,1,1,0,2,1,1,1,0,1,1,0,2,1,1,2,1,2])
原始数据=局部数据帧(原始数据)
原始_数据['color']='black'
原始数据源=列数据源(原始数据)
#空源,以便在选择数据之前绘图为空
source=ColumnDataSource(dict(物种=[],集合号=[],长度=[],重量=[],性别=[],颜色=[]))
###主要情节
图=图形(标题='长度-重量散点图',x轴标签='长度(厘米)',y轴标签='重量(克)',
tools=“平移、悬停、方框\缩放、重置、保存”,工具栏\位置=“右”,
绘图宽度=450,绘图高度=450)
圆(x='长度',y='重量',颜色='颜色',填充字母=1,源=源,线宽=2)
#选择物种
可用物种=列表(集合(原始物种数据)
可用物种。排序()
物种回调=CustomJS(args={'source':source,'original\u source':original\u source},
代码=”“
var数据=原始来源数据;
var source_data=source.data;
var物种_数据=数据[‘物种’];
变量长度_data=数据['length'];
var weight_data=数据[‘权重’];
var sex_id_data=数据['sex_id'];
var set_number_data=数据['set_number'];
var color_data=数据['color'];
所选物种的var=cb_对象值;
var source_length=source_数据['length'];
源_length.length=0;
var source_weight=source_数据['weight'];
来源重量长度=0;
var source_sex_id=source_数据['sex_id'];
source_sex_id.length=0;
var source_species=source_数据[‘species'];
源_物种长度=0;
var source_set_number=source_data['set_number'];
source_set_number.length=0;
var source_color=source_数据['color'];
source_color.length=0;
对于(变量i=0;i=0)
source_length.push(长度数据[i]);
来源重量推送(重量数据[i]);
来源物种推送(物种数据[i]);
source_set_number.push(set_number_data[i]);
源性id.push(性id数据[i]);
source_color.push(颜色数据[i]);
}
}
source.change.emit();
""")
multiselect_物种=multiselect(标题='物种:',值=[],选项=可用物种,宽度=240)
#multiselect_species.js_on_change('value',species_回调)
#选择集(多选)
#可用的集合=列表(集合(映射(str,原始集合数据['set\u number']))
可用\u集合=列表(集合(原始\u数据['set\u number']))
可用的\u set.sort()
set_callback=CustomJS(args={'source':source,'original_source':original_source},
代码=”“
var数据=原始来源数据;
var source_data=source.data;
var物种_数据=数据[‘物种’];
变量长度_data=数据['length'];
var weight_data=数据[‘权重’];
var sex_id_data=数据['sex_id'];
var set_number_data=数据['set_number'];
var color_data=数据['color'];
所选物种的var=cb_对象值;
var source_length=source_数据['length'];
源_length.length=0;
var source_weight=source_数据['weight'];
来源重量长度=0;
var source_sex_id=source_数据['sex_id'];
source_sex_id.length=0;
var source_species=source_数据[‘species'];
源_物种长度=0;
var source_set_number=source_data['set_number'];
source_set_number.length=0;
var source_color=source_数据['color'];
source_color.length=0;
对于(变量i=0;i=0){
source_length.push(长度数据[i]);
来源重量推送(重量数据[i]);
来源物种推送(物种数据[i]);
source_set_number.push(set_number_data[i]);
源性id.push(性id数据[i]);
source_color.push(颜色数据[i]);
}
}
source.change.emit();
""")
multiselect_set=multiselect(title='set:',value=[],options=available_set,width=240)
multiselect_set.js_on_change('value',set_回调)
#应根据选择的物种更新可用的集合
multiselect_species.js_on_change('value',species_回调,CustomJS)(args=dict(multiselect_set=multiselect_set,
可用集=可用集),
代码=”“
常量变量集=%s
multiselect_set.options=变量集。[cb_对象值]
multiselect_set.options=multiselect_set.options.join()
“”“%可用(U集))
#数据表
columns=[TableColumn(field=“species”,title=“common name”,width=100),
TableColumn(field=“set_number”,title=“set number”,宽度=100),
TableColumn(field=“length”,title=“length(cm)”,width=100),
TableColumn(field=“weight”,title=“weight(g)”,宽度=100),
TableColumn(field=“sex\u id”,title=“sex”,width=100)]
数据表=数据表(源=源,列=列,排序表
# Data handling
import pandas as pd

# Bokeh libraries
from bokeh.plotting import figure, output_file, show
from bokeh.embed import components
from bokeh.models import Toggle, ColumnDataSource, FactorRange, Callback, CustomJS
from bokeh.models.widgets import DataTable, NumberFormatter, TableColumn, HTMLTemplateFormatter
from bokeh.io import curdoc
from bokeh.layouts import row, column
from bokeh.models.widgets import TextInput, MultiSelect

# test data
original_data = dict(species = ['A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','A','B','C','D','E','A','A'],
length = [2, 10, 20, 40, 60, 80, 70, 50, 15, 36, 76, 74, 72, 44, 36, 18, 40, 64, 40, 64, 40, 30, 120],
weight = [2, 100, 150, 200, 420, 700, 600, 300, 200, 200, 620, 610, 601, 610, 601, 80, 205, 80, 800, 700, 240, 160, 800],
set_number = ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '3', '4', '1', '5', '1'],
sex_id = [2, 0, 0, 0, 2, 1, 1, 0, 2, 1, 1, 1, 0, 1, 1, 0, 2, 1, 1, 2, 1, 0, 2])

original_data = pd.DataFrame(original_data)
original_data['color'] = 'black'

original_source = ColumnDataSource(original_data)

# Empty source so the plot is empty before the data is selected
source = ColumnDataSource(dict(species = [], set_number = [], length = [], weight = [], sex_id = [], color = []))

### Main plot
plot = figure(title = 'Length-weight scatterplot', x_axis_label = 'length (cm)', y_axis_label = 'weight (g)',
        tools = "pan, hover, box_zoom, reset, save", toolbar_location = "right", 
        plot_width = 450, plot_height = 450)

plot.circle(x = 'length', y = 'weight', color = 'color', fill_alpha = 1, source = source, line_width = 2)

# Select species
available_species = list(set(original_data['species']))
available_species.sort()

code = """ 
    var data = original_source.data;
    var source_data = source.data;

    var species_data = data['species'];
    var length_data = data['length'];
    var weight_data = data['weight'];
    var sex_id_data = data['sex_id'];
    var set_number_data = data['set_number'];
    var color_data = data['color'];
    var selected_species = cb_obj.value;

    var source_length = source_data['length'];
    source_length.length = 0;

    var source_weight = source_data['weight'];
    source_weight.length = 0;

    var source_sex_id = source_data['sex_id'];
    source_sex_id.length = 0;

    var source_species = source_data['species'];
    source_species.length = 0;

    var source_set_number = source_data['set_number'];
    source_set_number.length = 0;

    var source_color = source_data['color'];
    source_color.length = 0;
    unique_sets = []
    for (var i = 0; i < length_data.length; i++) {
        if (selected_species.indexOf(species_data[i]) >= 0)  {
            source_length.push(length_data[i]);
            source_weight.push(weight_data[i]);
            source_species.push(species_data[i]);
            source_set_number.push(set_number_data[i]);
            source_sex_id.push(sex_id_data[i]);
            source_color.push(color_data[i]);

            if ( !unique_sets.includes(set_number_data[i]) ) {
                unique_sets.push(set_number_data[i])
            }
        }
    }

    source.change.emit();
    multiselect_set.options = unique_sets
"""

print(source.data['set_number'])

# species_callback = CustomJS(args = {'source': source, 
#                                     'original_source': original_source,
#                                     'multiselect_set': multiselect_set,
#                                     },
#                             code = code)

multiselect_species = MultiSelect(title = 'Species:', value = [], options = available_species, width = 240)
#multiselect_species.js_on_change('value', species_callback)

# Select set (multiselect)
#available_set = list(set(map(str, original_data['set_number'])))
available_set = list(set(original_data['set_number']))
available_set.sort()

set_callback = CustomJS(args = {'source': source, 'original_source': original_source},
code = """
var data = original_source.data;
var source_data = source.data;

var species_data = data['species'];
var length_data = data['length'];
var weight_data = data['weight'];
var sex_id_data = data['sex_id'];
var set_number_data = data['set_number'];
var color_data = data['color'];
var selected_species = cb_obj.value;

var source_length = source_data['length'];
source_length.length = 0;

var source_weight = source_data['weight'];
source_weight.length = 0;

var source_sex_id = source_data['sex_id'];
source_sex_id.length = 0;

var source_species = source_data['species'];
source_species.length = 0;

var source_set_number = source_data['set_number'];
source_set_number.length = 0;

var source_color = source_data['color'];
source_color.length = 0;

 for (var i = 0; i < length_data.length; i++) {
     if (selected_species.indexOf(set_number_data[i]) >= 0) { 
         source_length.push(length_data[i]);
         source_weight.push(weight_data[i]);
         source_species.push(species_data[i]);
         source_set_number.push(set_number_data[i]);
         source_sex_id.push(sex_id_data[i]);
         source_color.push(color_data[i]);
     }
 }
 source.change.emit();
 """)

multiselect_set = MultiSelect(title = 'Set:', value = [], options = available_set, width = 240)
multiselect_set.js_on_change('value', set_callback)


species_callback = CustomJS(args = {'source': source, 
                                    'original_source': original_source,
                                    'multiselect_set': multiselect_set,
                                    },
                            code = code)

# The sets available should be updated depending on the species chosen
multiselect_species.js_on_change('value', species_callback)

# Data table
columns = [TableColumn(field = "species", title = "common name", width = 100),
           TableColumn(field = "set_number", title = "set number", width = 100),
           TableColumn(field = "length", title = "length (cm)", width = 100),
           TableColumn(field = "weight", title = "weight (g)", width = 100),
           TableColumn(field = "sex_id", title = "sex", width = 100)]

data_table = DataTable(source = source, columns = columns, sortable = True, editable = True, width = 500, height = 450,
                        fit_columns = True)

# Set up widgets layout
widgets_layout = column(multiselect_species, multiselect_set)

# Set up figures layout
figures_layout = row(plot, data_table)

# Set up page layout
page_layout = row(widgets_layout, figures_layout)

show(page_layout)