Jupyter Notebook构建Python仪表盘:交互式图表重复添加问题求助
如何在Jupyter Notebook中创建混合交互式与静态图表的仪表盘(解决重复添加图表问题)
首先明确:完全可以在Jupyter Notebook中创建同时包含交互式和静态图表的仪表盘,你遇到的图表重复添加问题,核心是技术栈混用和绘图输出方式错误导致的。
问题核心原因
- 使用
matplotlib.pyplot.show():每次调用都会在输出区域新增一个图表实例,而非替换原有内容 - 混用ipywidgets和Panel组件:两种框架的状态管理逻辑冲突,导致交互触发时无法正确更新组件
- 用
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()
关键修改说明
- 绘图函数返回Figure:所有绘图函数改用
plt.subplots()创建fig和ax,最后返回fig,不再调用plt.show(),让Panel能够正确管理图表的更新和替换 - 统一使用Panel组件:用
pn.widgets.Select替代ipywidgets的Dropdown,避免跨框架的状态冲突 - 动态文本用Markdown组件:将原本的
print()输出改为返回Markdown字符串,通过Panel绑定后实现文本区域的更新而非追加 - 布局优化:将选择器和对应文本放在同一列,让交互逻辑更直观,同时设置
sizing_mode='stretch_width'适配Jupyter窗口宽度
内容的提问来源于stack exchange,提问作者Marco M
相关产品推荐
相关产品推荐

