Jupyter中交互式过滤后KDE动画绘图问题求助
我来帮你修复这个问题,让你的KDE动画能响应ipywidgets的过滤变化,并且按月正确切换。咱们先看修正后的完整代码,再拆解每一处的改进:
修正后的完整代码
import ipywidgets as widgets from ipywidgets import interact_manual import matplotlib.pyplot as plt import seaborn as sns from matplotlib import animation, rc from IPython.display import HTML import pandas as pd # 假设你的widgets已经提前定义好(比如下面的示例,根据你的实际数据调整) # channel_widget = widgets.SelectMultiple(options=df['SALES CHANNEL'].unique(), description='Channel') # currency_widget = widgets.Dropdown(options=df['CURRENCY'].unique(), description='Currency') # cumulative_widget = widgets.Checkbox(value=False, description='Use Cumulative') # 全局设置动画渲染模式,确保在Notebook中正常显示 rc('animation', html='jshtml') def create_kde_animation(channel, currency, use_cumulative): # 1. 先获取最新的过滤后数据 filtered_df = df[(df['SALES CHANNEL'].isin(channel)) & (df['CURRENCY'] == currency)] # 2. 初始化绘图画布 fig, ax = plt.subplots() ax.set_xlim(0, 17500) ax.set_xlabel('Price') ax.set_ylabel('Density') # 修正月份拼写错误(原代码的"Novemer"改为"November") month_list = ['', 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] def init(): # 初始化时清空轴,避免残留旧图形 ax.cla() ax.set_xlim(0, 17500) ax.set_xlabel('Price') ax.set_ylabel('Density') return ax, def animate(i): # i代表当前月份(1-12,匹配你的MONTH列数值类型) current_month = i # 筛选当月的过滤后数据 monthly_data = filtered_df[filtered_df['MONTH'] == current_month] ax.cla() ax.set_xlim(0, 17500) ax.set_xlabel('Price') ax.set_ylabel('Density') ax.set_title(f'Price Density {month_list[current_month]}') if not monthly_data.empty: # 计算两组KDE所需数据:家族平均价格、所有单品价格 family_avg_price = monthly_data.groupby('FAMILY')[' PRICE/UNIT (EGP) '].mean() all_unit_prices = monthly_data[' PRICE/UNIT (EGP) '] # 绘制两条KDE曲线,添加图例区分 sns.kdeplot(family_avg_price, ax=ax, label='Family Avg Price', cumulative=use_cumulative) sns.kdeplot(all_unit_prices, ax=ax, label='All Unit Prices', cumulative=use_cumulative) ax.legend() else: # 当月无数据时显示提示 ax.text(0.5, 0.5, 'No Data Available', ha='center', va='center', transform=ax.transAxes) return ax, # 创建动画:frames设置为1-12(对应12个月份),interval是切换间隔(毫秒) anim = animation.FuncAnimation(fig, animate, init_func=init, frames=range(1, 13), interval=1000, blit=True) # 关闭静态画布,避免额外显示空图 plt.close(fig) # 返回动画的HTML对象,让Notebook渲染显示 return HTML(anim.to_jshtml()) # 绑定过滤组件与动画生成函数,每次点击Run都会更新动画 interact_manual(create_kde_animation, channel=channel_widget, currency=currency_widget, use_cumulative=cumulative_widget)
关键改进点说明
绑定过滤与动画更新
把动画生成逻辑放到了create_kde_animation函数中,并用interact_manual和你的过滤widget绑定。现在每次调整过滤条件并点击Run,都会重新执行数据过滤并生成最新的动画,彻底解决了原代码不响应过滤变化的问题。动态获取月度数据
在animate函数里,每次根据当前帧i(代表月份)重新筛选当月的过滤后数据,而不是在初始化时就固定死数据,这样动画每切换一个月,都会用对应月份的最新过滤数据绘制KDE。完善绘图逻辑
- 每次绘制前用
ax.cla()清空轴,避免旧曲线残留; - 重新设置坐标轴范围、标签和标题,保证每个月份的图都有正确的显示;
- 添加了空数据判断,如果当月没有符合条件的数据,会显示友好提示,避免报错。
- 每次绘制前用
响应
use_cumulative参数
在sns.kdeplot中加入了cumulative=use_cumulative参数,现在勾选"Use Cumulative"后,会自动切换为累积分布的KDE曲线。细节修复
- 修正了月份列表里的拼写错误("Novemer"→"November");
- 用
plt.close(fig)关闭静态画布,避免Notebook里额外显示空图; - 添加了图例,方便区分两条KDE曲线的含义。
小提醒
如果你的df['MONTH']列存储的是字符串(比如"Jan"),需要把frames和筛选逻辑改成对应字符串的范围,比如frames=['Jan','Feb',...,'Dec'],并调整monthly_data = filtered_df[filtered_df['MONTH'] == current_month]的匹配逻辑。
内容的提问来源于stack exchange,提问作者Khaled Choucri
相关产品推荐
相关产品推荐

