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

Jupyter Notebook构建Python仪表盘:交互式图表重复添加问题求助

如何在Jupyter Notebook中创建混合交互式与静态图表的仪表盘(解决重复添加图表问题)

首先明确:完全可以在Jupyter Notebook中创建同时包含交互式和静态图表的仪表盘,你遇到的图表重复添加问题,核心是技术栈混用和绘图输出方式错误导致的。

问题核心原因

  1. 使用matplotlib.pyplot.show():每次调用都会在输出区域新增一个图表实例,而非替换原有内容
  2. 混用ipywidgets和Panel组件:两种框架的状态管理逻辑冲突,导致交互触发时无法正确更新组件
  3. 用print()输出动态文本:同样会不断追加内容,而非更新指定区域

修复后的完整代码

import matplotlib.pyplot as plt
import panel as pn
import pandas as pd

# 初始化Panel扩展(Jupyter环境中需要)
pn.extension()

# 示例数据,可替换为真实数据
data = pd.DataFrame({
    'Meets end target by completion of project': ['Yes', 'No', 'Yes', 'No', 'Yes']*10,
    'SDG Goal': ['SDG 1', 'SDG 2', 'SDG 3', 'SDG 1', 'SDG 2']*10,
    'Years until End target is met': [0.5, 1.2, 0, 0.8, 0]*10,
    'Total Project Length (Years)': [2.0, 3.5, 1.8, 2.5, 3.0]*10
})

# 静态图表1:返回Figure对象,不调用plt.show()
def plot_graph_1(data):
    target_counts = data['Meets end target by completion of project'].value_counts()
    fig, ax = plt.subplots(figsize=(8, 6))
    target_counts.plot(kind='bar', color=['green', 'red'], ax=ax)
    ax.set_title('Projects Meeting End Target by Completion of Project')
    ax.set_xlabel('Meets End Target')
    ax.set_ylabel('Number of Projects')
    ax.set_xticklabels(ax.get_xticklabels(), rotation=0)
    return fig

# 交互式图表2:返回Figure对象,接收selected_sdg参数
def plot_graph_2(data, selected_sdg):
    sdg_data = data[data['SDG Goal'] == selected_sdg]
    sdg_counts = sdg_data['Meets end target by completion of project'].value_counts()
    yes_color = 'green'
    no_color = 'red'
    fig, ax = plt.subplots(figsize=(6, 4))
    # 确保Yes/No顺序,缺失类别补0
    sdg_counts.reindex(['Yes', 'No'], fill_value=0).plot(kind='bar', color=[yes_color, no_color], ax=ax)
    ax.set_title(f'Meeting End Target by Completion Date for {selected_sdg}')
    ax.set_xlabel('Meets End Target')
    ax.set_ylabel('Number of Projects')
    ax.set_xticklabels(ax.get_xticklabels(), rotation=0)
    return fig

# 静态图表3:返回Figure对象
def plot_graph_3(data):
    avg_project_length_by_sdg = data.groupby('SDG Goal')['Total Project Length (Years)'].mean().sort_values()
    colors = plt.cm.tab10.colors[:len(avg_project_length_by_sdg)]
    fig, ax = plt.subplots(figsize=(10, 6))
    avg_project_length_by_sdg.plot(kind='bar', color=colors, ax=ax)
    ax.set_title('Average Time to reach SDG Goal')
    ax.set_xlabel('SDG Goal')
    ax.set_ylabel('Average Total Project Length (Years)')
    ax.set_xticklabels(ax.get_xticklabels(), rotation=45)
    return fig

# 交互式文本1:返回Markdown格式文本,替换print()
def get_interactive_text_1(data, selected_sdg):
    sdg_data = data[(data['SDG Goal'] == selected_sdg) & (data['Meets end target by completion of project'] == 'No')]
    avg_time = sdg_data['Years until End target is met'].mean()
    return f"""### 统计信息
SDG {selected_sdg}项目完成后,平均还需要**{avg_time:.2f}年**达成最终目标"""

# 交互式文本2:返回Markdown格式文本
def get_interactive_text_2(data, selected_sdg):
    sdg_data = data[data['SDG Goal'] == selected_sdg]
    avg_project_length = sdg_data['Total Project Length (Years)'].mean()
    return f"""### 项目时长统计
SDG {selected_sdg}的平均项目总时长为**{avg_project_length:.2f}年**"""

# 使用Panel的Select组件(替代ipywidgets.Dropdown)
sdg_selector = pn.widgets.Select(options=sorted(data['SDG Goal'].unique()), name='选择SDG目标')

# 绑定组件:静态图表直接绑定,交互式组件关联selector
plot1 = pn.bind(plot_graph_1, data)
plot2 = pn.bind(plot_graph_2, data, sdg_selector)
text1 = pn.bind(get_interactive_text_1, data, sdg_selector)
plot3 = pn.bind(plot_graph_3, data)
text2 = pn.bind(get_interactive_text_2, data, sdg_selector)

# 构建仪表盘布局
dashboard = pn.Column(
    '# SDG项目仪表盘',
    pn.Row(
        pn.Column(sdg_selector, text1),
        plot2
    ),
    pn.Row(
        plot1,
        pn.Column(plot3, text2)
    ),
    sizing_mode='stretch_width'
)

# 在Jupyter中显示仪表盘
dashboard.servable()

关键修改说明

  1. 绘图函数返回Figure:所有绘图函数改用plt.subplots()创建fig和ax,最后返回fig,不再调用plt.show(),让Panel能够正确管理图表的更新和替换
  2. 统一使用Panel组件:用pn.widgets.Select替代ipywidgets的Dropdown,避免跨框架的状态冲突
  3. 动态文本用Markdown组件:将原本的print()输出改为返回Markdown字符串,通过Panel绑定后实现文本区域的更新而非追加
  4. 布局优化:将选择器和对应文本放在同一列,让交互逻辑更直观,同时设置sizing_mode='stretch_width'适配Jupyter窗口宽度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:56:00