我认为您的示例甚至不应该构建文档,您的文本输入和多选择模型都具有相同的ID,这可能是选项卡显示混乱的原因。
我的解决方案类似于Hyry的,但有一个更通用的功能,可以使用两种不同的东西共享属性:
model.properties_with_values()。
可以与任何bokeh模型一起使用,并返回所有属性的字典:模型的值对。它在IPython中主要用于探索Bokeh对象和调试
document.select('type':模型)
生成文档中所需类型的所有小部件
然后,我过滤掉那些与输入小部件不共享相同标签的小部件,这样可以避免“同步”其他输入/不与box_maker()生成的多重选择。我使用标签是因为不同的型号不能有相同的名称。
当您更改textinput值时,它将更改更新函数中关联的multisect,但它也将更改所有其他textinput并以相同的方式触发它们的更新。因此,每个输入触发器都会更新一次并更改其各自的多选择选项(而不是每次都进行多次更新,因为它是一个“on-change”回调,如果为新输入赋予相同的值,则不会触发)。
对于multisect,更新的第一个触发器将执行该操作,但由于它更改了其他multisect的值,因此它仍会触发与multisect小部件相同的次数。
from bokeh.io import curdoc
from bokeh.layouts import widgetbox
from bokeh.models import TextInput, MultiSelect
from bokeh.models.widgets import Panel, Tabs
import pandas as pd
from functools import partial
df = pd.DataFrame(["apples", "oranges", "grapes"], columns=["fruits"])
def sync_attr(widget):
prop = widget.properties_with_values() # dictionary of attr:val pairs of the input widget
for elem in curdoc().select({'type':type(widget)}): # loop over widgets of the same type
if (elem!=widget) and (elem.tags==widget.tags): # filter out input widget and those with different tags
for key in prop: # loop over attributes
setattr(elem,key,prop[key]) # copy input properties
def update(attr,old,new,widget,other_widget):
print("\ndf['fruits']: {}".format(list(df['fruits'])))
print("{} : {} changed: Old [ {} ] -> New [ {} ]".format(str(widget),attr, old, new))
if type(widget)==TextInput:
col_data = list(df[df['fruits'].str.contains(new)]['fruits'])
print("col_date: {}".format(col_data))
other_widget.update(options = sorted(list(col_data)))
sync_attr(widget)
def box_maker():
multiselect = multiselect = MultiSelect(title = 'multiselect',tags=['in_box'],value = [],options = list(df["fruits"]))
input_box = TextInput(title = 'input',tags=['in_box'],value='Enter you choice')
multiselect.on_change('value',partial(update,widget=multiselect,other_widget=input_box))
input_box.on_change('value',partial(update,widget=input_box,other_widget=multiselect))
return widgetbox(input_box, multiselect)
box_list = [box_maker() for i in range(2)]
tabs = [Panel(child=box,title="Panel{}".format(i)) for i,box in enumerate(box_list)]
tabs = Tabs(tabs=tabs)
curdoc().add_root(tabs)
请注意,在multisect中突出显示的选项可能看起来不一致,但当每个选项的值/选项都正确更改时,这似乎是可视的。
但是,除非您在将小部件放入面板时特别关注布局外观,否则您可以将一个输入和多个选择置于外部,并编写它们的回调以处理不同面板中的内容。