You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 with level_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 Column layout instead of multiple curdoc().add_root() calls. This keeps your document structure organized and avoids messy overlapping widgets.
  • Renamed Functions: I renamed your duplicate update functions to update_date and update_level to avoid confusion and bugs.

内容的提问来源于stack exchange,提问作者Anil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:53:40