Я изо всех сил пытаюсь внедрить взаимозависимые мультиселектные меню в Боке. Приведенный ниже код почти работает, но когда я выбираю данный вид в первом множественном меню (скажем, вид E), а затем выбираю набор во втором множественном меню (набор 1), он возвращает все виды для этого набора (A и E) вместо возврата только выбранных видов в первом меню (E). Я не уверен, как решить эту проблему. Мысли?
# Data handling
import pandas as pd
# Bokeh libraries
from bokeh.plotting import figure, output_file, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, Legend
from bokeh.models.widgets import DataTable, TableColumn
from bokeh.layouts import column, row
from bokeh.models.widgets import MultiSelect, Button
# 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=[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=[], color=[]))
# Main plot
plot = figure(title='Length-weight scatterplot', x_axis_label='length (cm)', y_axis_label='weight (g)')
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_data = data['sex'];
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 = source_data['sex'];
source_sex.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;
var 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.push(sex_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'])
multiselect_species = MultiSelect(title='Species:', value=[], options=available_species, width=235)
# Select set (multiselect)
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_data = data['sex'];
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 = source_data['sex'];
source_sex.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.push(sex_data[i]);
source_color.push(color_data[i]);
}
}
source.change.emit();
""")
multiselect_set = MultiSelect(title='Set:', value=[], options=available_set, width=235)
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)
# # Clear button to reset multiselect_set
clear_set_button = Button(label="Clear set selection", button_type="primary", width=235)
clear_set_callback = CustomJS(args=dict(s=multiselect_set), code="s.value = []")
clear_set_button.js_on_event('button_click', clear_set_callback)
# Clear button to reset multiselect_species
clear_species_button = Button(label="Clear species selection", button_type="primary", width=235)
clear_species_callback = CustomJS(args=dict(s=multiselect_species), code="s.value = []")
clear_species_button.js_on_event('button_click', clear_species_callback)
# Data table
columns = [TableColumn(field="species", title="common name", width=200),
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", title="sex", width=50)]
data_table = DataTable(source=source, columns=columns, sortable=True, editable=True, width=500, height=450,
fit_columns=True, margin=(100, 0, 0, 0))
# Set up widgets layout
widgets_layout = column(multiselect_species, clear_species_button, multiselect_set, clear_set_button)
# Set up figures layout
figures_layout = row(plot, data_table)
# Set up page layout
page_layout = row(widgets_layout, figures_layout)
show(page_layout)