问题
Below is the code for a small working example of a Bokeh dashboard.
When you make a selection in the first dropdown menu, the second one is updated dynamically and the chart is updated with a new source. This works for options A1/A2 because the data arrays are the same length.
Once you select option B1 in the first dropdown, the second dropdown changes to B2.
But the source update doesn't happen because you cant get the Yselector.value
.
How can you retrieve the Yselector.value
without using Bokeh's on_change
method and pass it to a function like source_selector
?
import numpy as np
import pandas as pd
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Tabs, Select
from bokeh.layouts import column, row, Spacer
from bokeh.io import curdoc
from bokeh.plotting import figure, curdoc, show
#Plotting points on initial chart.
df_AB = pd.DataFrame(np.random.randint(0,100,size=(500, 2)), columns=list('XY'), index=[str(i) for i in range(1,500+1)])
pointchart=figure(plot_width=800, plot_height=700, tools=['lasso_select','box_select','wheel_zoom'],title="Point scatter")
pointchart_source= ColumnDataSource(df_AB[["X","Y"]])
pointchart.circle("X","Y",source=pointchart_source)
#Dropdown X
selectoroptions=['','Series A1', 'Series A2','Series B1','Series B2']
Xselector = Select(title="Dropdown X:", value="", options=selectoroptions)
#Dropdown Y
selectoroptions=['','Series A1', 'Series A2','Series B1','Series B2']
Yselector = Select(title="Dropdown Y:", value="", options=selectoroptions)
#Will list multiple sources to feed the chart based on dropdown selection.
def source_selector(selection):
if selection=='Series A1':
newvalues= pd.Series(list(np.random.randint(100, size=500)),name="")
elif selection=='Series A2':
newvalues= pd.Series(list(np.random.randint(200, size=500)),name="")
elif selection=='Series B1':
newvalues= pd.Series(list(np.random.randint(20, size=20)),name="")
elif selection=='Series B2':
newvalues= pd.Series(list(np.random.randint(10, size=20)),name="")
return newvalues
#Once dropdown X seelction is made, the options of dropdown Y will dynamically change.
#Data used for X axis is updated.
def X_switch_selection_and_source(attr, old, new):
if new == '':
pointchart_source.data = ColumnDataSource(df_AB[["X","Y"]]).data
#Other dropdown changed dynamically
elif new=='Series A1':
Yselector.options=['Series A2']
elif new=='Series A2':
Yselector.options=['Series A1']
elif new=='Series B1':
Yselector.options=['Series B2']
elif new=='Series B2':
Yselector.options=['Series B1']
#Updating source based on this dropdown's selection/ X values.
new_x_values=source_selector(new)
#Issue is right here. This line will only work if y is the same length as new x.
new_y_values=list(pointchart_source.data["Y"])
#If the lenghths are different I want to update the source for y by getting the y dropdown value.
if len(new_x_values)!= len(new_y_values):
new_y_values=source_selector(Yselector.value) # Does not get the dynamically changed value in the Y dropdown.
sourcedf=pd.DataFrame({"X":new_x_values,"Y":new_y_values})
pointchart_source.data= ColumnDataSource(sourcedf).data
Xselector.on_change("value", X_switch_selection_and_source)
#Show
layout=row(column(Xselector,Yselector, Spacer(width=400, height=500)),pointchart)
curdoc().add_root(layout)
!powershell -command {'bokeh serve --show Bokeh_dropdown_helped_v2.ipynb'}
My goal is for the user to be able to make selections from the dropdowns and for the other dropdown to show only the appropriate selections based on the first selection.
The data used for the axis' will be updated based on the selections.
Thank you for any advice.
回答1:
Change the Select widget values instead of its options. If you change the options, you must make sure that its value is one of the options.
elif new=='Series A1':
Yselector.value='Series A2'
elif new=='Series A2':
Yselector.value='Series A1'
elif new=='Series B1':
Yselector.value='Series B2'
elif new=='Series B2':
Yselector.value='Series B1'
来源:https://stackoverflow.com/questions/55694687/get-bokeh-dropdown-value-without-interaction