如何实现选择新文件时自动更新Canvas中的Matplotlib图表?
JSON数据可视化GUI图表更新问题
问题描述
我正在开发一个用于可视化JSON数据的GUI,目前遇到的问题是无法让Canvas中的图表更新,仅在点击窗口最大化/最小化按钮时才会更新。请问是否有办法在选择新文件时更新图表?
界面状态说明
- 图表未及时更新状态:选择新文件后图表区域无内容,仅在窗口缩放(最大化/最小化)后才显示对应数据的图表
- GUI界面:包含用于选择文件的列表框和图表展示Canvas区域
相关代码
##### Canvas #### figure = plt.figure() canvas = FigureCanvasTkAgg(figure, master=inspect_data) canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) ###### file gets selected ##### def items_selected(d): plt.clf() selected_indices = vores_listebox.curselection() selected_json = ",".join([vores_listebox.get(i) for i in selected_indices]) full_file_path = path_us + selected_json open_json = js.load(open(full_file_path, "r")) time = [open_json['XML_Data'] ['Wsk3Vectors']['X_Axis']['Values']['float']] rpm = [open_json['XML_Data']['Wsk3Vectors'] ['Y_AxesList']['AxisData'][0]['Values']['float']] torque = [open_json['XML_Data']['Wsk3Vectors'] ['Y_AxesList']['AxisData'][1]['Values']['float']] current = [open_json['XML_Data']['Wsk3Vectors'] ['Y_AxesList']['AxisData'][2]['Values']['float']] angle = [open_json['XML_Data']['Wsk3Vectors'] ['Y_AxesList']['AxisData'][3]['Values']['float']] depth = [open_json['XML_Data']['Wsk3Vectors'] ['Y_AxesList']['AxisData'][4]['Values']['float']] ###### Using Matlib.pyplot to plot 5 graphs ###### plt.rcParams["figure.figsize"] = (7, 10) plt.subplot(5, 1, 1) plt.scatter(time, rpm, c="b", linewidths=2, marker=",", edgecolor="b", s=1, alpha=0.5) plt.title(selected_json) plt.gca().axes.xaxis.set_ticklabels([]) plt.ylabel("RPM") plt.grid() plt.subplot(5, 1, 2) plt.scatter(time, torque, c="g", linewidths=1, marker=",", edgecolor="g", s=1, alpha=0.3) plt.gca().axes.xaxis.set_ticklabels([]) plt.ylabel("Torque [Nm]") plt.grid() plt.subplot(5, 1, 3) plt.scatter(time, current, c="r", linewidths=2, marker=",", edgecolor="r", s=1, alpha=0.5) plt.gca().axes.xaxis.set_ticklabels([]) plt.ylabel("Current [Amps]") plt.grid() plt.subplot(5, 1, 4) plt.scatter(time, angle, c="m", linewidths=2, marker=",", edgecolor="m", s=1, alpha=0.5) plt.gca().axes.xaxis.set_ticklabels([]) plt.ylabel("Angle [RAD]") plt.grid() plt.subplot(5, 1, 5) plt.scatter(time, depth, c="c", linewidths=2, marker=",", edgecolor="c", s=1, alpha=0.5) plt.xlabel("Time [ms]") plt.ylabel("Depth [mm]") plt.grid() vores_listebox.bind('<<ListboxSelect>>', items_selected)
我已尝试使用root.update()、Canvas.update()等命令,但均无效,恳请提供解决帮助!
解决方案
核心修复:触发Canvas重绘
问题根源是绘制完图表后未主动通知FigureCanvasTkAgg更新界面。在items_selected函数的最后,添加以下两行代码即可触发实时更新:
canvas.draw() canvas.flush_events()
修改后的完整函数结尾如下:
plt.subplot(5, 1, 5) plt.scatter(time, depth, c="c", linewidths=2, marker=",", edgecolor="c", s=1, alpha=0.5) plt.xlabel("Time [ms]") plt.ylabel("Depth [mm]") plt.grid() # 新增:触发图表更新 canvas.draw() canvas.flush_events()
canvas.draw():强制重新渲染图表内容canvas.flush_events():处理所有待处理的GUI事件,确保绘制结果立即显示
优化建议:改用面向对象绘图方式
避免混用pyplot全局状态和FigureCanvasTkAgg,改用面向对象方式操作figure对象,减少状态冲突,代码更易维护:
# 初始化Canvas时设置图尺寸 figure = plt.figure(figsize=(7, 10)) canvas = FigureCanvasTkAgg(figure, master=inspect_data) canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True) def items_selected(d): figure.clear() # 用figure.clear()替代plt.clf() # ... 读取JSON数据部分保持不变 ... # 创建5行1列的子图数组 axs = figure.subplots(5, 1) # 绘制第一个子图 axs[0].scatter(time, rpm, c="b", linewidths=2, marker=",", edgecolor="b", s=1, alpha=0.5) axs[0].set_title(selected_json) axs[0].set_ylabel("RPM") axs[0].tick_params(axis='x', labelbottom=False) # 隐藏x轴标签 axs[0].grid(True) # 绘制第二个子图 axs[1].scatter(time, torque, c="g", linewidths=1, marker=",", edgecolor="g", s=1, alpha=0.3) axs[1].set_ylabel("Torque [Nm]") axs[1].tick_params(axis='x', labelbottom=False) axs[1].grid(True) # 绘制第三个子图 axs[2].scatter(time, current, c="r", linewidths=2, marker=",", edgecolor="r", s=1, alpha=0.5) axs[2].set_ylabel("Current [Amps]") axs[2].tick_params(axis='x', labelbottom=False) axs[2].grid(True) # 绘制第四个子图 axs[3].scatter(time, angle, c="m", linewidths=2, marker=",", edgecolor="m", s=1, alpha=0.5) axs[3].set_ylabel("Angle [RAD]") axs[3].tick_params(axis='x', labelbottom=False) axs[3].grid(True) # 绘制第五个子图 axs[4].scatter(time, depth, c="c", linewidths=2, marker=",", edgecolor="c", s=1, alpha=0.5) axs[4].set_xlabel("Time [ms]") axs[4].set_ylabel("Depth [mm]") axs[4].grid(True) # 触发更新 canvas.draw() canvas.flush_events()
内容的提问来源于stack exchange,提问作者Hvalendahlen
相关产品推荐
相关产品推荐

