Bokeh中切换日期Select组件时移除旧层级Select组件的技术问询
Fix for Duplicate Level Select Widgets When Switching Dates in Bokeh
Got it, let's solve this duplicate Select widget issue. The problem right now is that every time you pick a new date, you're adding a brand new level_selection widget directly to the document root with curdoc().add_root(), which leaves all the old ones hanging around. Instead of spawning new roots every time, we can use a fixed container to hold the level select widget—then we just clear and re-populate that container when the date changes.
Key Changes to Your Code
Here's the adjusted version of your code with fixes explained:
from bokeh.models.widgets import Div, Paragraph, Select, Tabs, Panel, WidgetBox, Column, TextInput from bokeh.models import CustomJS import numpy as np import pandas as pd import os from os.path import join, dirname # Initialize welcome banner welcome_message = 'Operator selected: (none)' text_banner = Paragraph(text=welcome_message, width=200, height=100) def callback_print(text_banner=text_banner): user_input = str(cb_obj.value) welcome_message = 'Operator selected: ' + user_input text_banner.text = welcome_message tabs.reset.emit() def my_text_input_handler(attr, old, new): print("Previous label: " + old) print("Updated label: " + new) root = join(dirname(__file__), str(new)) dirlist = [item for item in os.listdir(root) if os.path.isdir(os.path.join(root, item))] available_date = dirlist + ['None'] # Update date select options when operator changes date_selection.options = available_date date_selection.value = 'None' # Clear level container to avoid stale widgets level_container.children = [] # Create a fixed container to hold the level select widget (this stays in the document) level_container = WidgetBox() def update_date(attr, old, new_date): if new_date == 'None': # Clear level select if user picks "None" for date level_container.children = [] return # Fetch available levels for the selected date root1 = join(dirname(__file__), str(text_input.value), str(new_date)) dirlist1 = [item for item in os.listdir(root1) if os.path.isdir(os.path.join(root1, item))] available_level = dirlist1 + ['None'] # Clear the container first to remove old level select, then add the new one level_container.children = [] level_selection = Select(title="Select a Level : ", value='None', options=available_level) level_selection.on_change('value', update_level) level_container.children.append(level_selection) def update_level(attr, old, new_level): if new_level == 'None': return # Load and process your data here user_data = pd.read_csv(join(dirname(__file__), str(text_input.value), str(date_selection.value), str(new_level), 'test1.txt'), sep=",", na_filter=None) data = user_data.copy() # Add your plotting/data handling logic here # Initialize core widgets text_input = TextInput(title="Enter operator Name:", callback=CustomJS.from_py_func(callback_print), css_classes=['customTextInput']) text_input.on_change('value', my_text_input_handler) date_selection = Select(title="Select a date : ", value='None', options=['None']) date_selection.on_change('value', update_date) # Assume your tabs (tab1 to tab7) are defined here # tabs = Tabs(tabs=[tab1, tab2, tab3, tab4, tab5, tab6, tab7]) # Build a single clean layout title = Div(text="<h1>Your Dashboard Title</h1>") layout = Column( title, tabs, text_banner, WidgetBox(text_input), WidgetBox(date_selection), level_container, sizing_mode='scale_width' ) # Set up the document curdoc().clear() curdoc().add_root(layout)
What Changed & Why
- Fixed Container: We created
level_container = WidgetBox()—this is a single, persistent container in your layout. Instead of adding new level selects directly to the document root, we add them to this container. - Clear Before Adding: In
update_date, we first empty the container withlevel_container.children = []before adding the new level select. This guarantees only the latest widget exists. - Clean 'None' Handling: We added logic to clear the container if the user selects "None" for the date, so no stale level select stays visible.
- Single Root Layout: All widgets are now part of one
Columnlayout instead of multiplecurdoc().add_root()calls. This keeps your document structure organized and avoids messy overlapping widgets. - Renamed Functions: I renamed your duplicate
updatefunctions toupdate_dateandupdate_levelto avoid confusion and bugs.
内容的提问来源于stack exchange,提问作者Anil
相关产品推荐
相关产品推荐

