Matplotlib双动态图表问题:左侧空白、Y轴刻度失效及迭代器异常
进程监控工具双图表问题修复方案
问题1:动态滚动图表左侧空白
根因
依赖FuncAnimation传入的i作为迭代计数器,但该参数在动画初始化阶段会重复传入0,导致前两次循环X轴范围设置错误,出现左侧空白。
修复方案
在类内部维护独立计数器,替代FuncAnimation传入的i:
- 在
__init__方法中添加self.counter = 0初始化计数器 - 在
animate方法中使用self.counter替代原i,每次循环完成后执行自增操作
问题2:Y轴刻度设置失效
根因
locator_params(axis="y", nbins=8)仅能减少刻度数量,无法强制增加刻度;- 每次调用
graph.clear()后轴配置会被重置,原样式设置逻辑存在覆盖问题,导致仅第二个图表的刻度配置生效。
修复方案
改用MaxNLocator强制指定刻度数量,确保每次清除图表后重新应用配置:
- 导入
from matplotlib.ticker import MaxNLocator - 在
set_graph_style方法中替换locator_params为graph.yaxis.set_major_locator(MaxNLocator(nbins=8, integer=True))
完整修复代码
import tkinter as tk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.figure import Figure import matplotlib.animation as animation from matplotlib.ticker import MaxNLocator import psutil class App(tk.Tk): def __init__(self): super().__init__() self.title("Graph Test") self.geometry("800x300") self.figure = Figure(figsize=(8, 3), dpi=100) self.cpu_graph = self.figure.add_subplot(121) self.set_graph_style(self.cpu_graph) self.memory_graph = self.figure.add_subplot(122) self.set_graph_style(self.memory_graph) canvas = FigureCanvasTkAgg(self.figure, self) canvas.get_tk_widget().grid(row=0, column=0) self.frame_length = 10 self.x_list = list(range(self.frame_length)) self.cpu_y_list = [-1] * self.frame_length self.memory_y_list = [-1] * self.frame_length # 维护独立计数器,替代FuncAnimation传入的i self.counter = 0 self.anim = animation.FuncAnimation(self.figure, self.animate, interval=1000) def animate(self, _): # 使用自定义计数器计算X轴范围 lower_limit = self.counter upper_limit = self.counter + self.frame_length self.x_list.append(self.counter + self.frame_length) self.cpu_y_list.append(psutil.cpu_percent()) self.memory_y_list.append(psutil.virtual_memory().percent) if len(self.cpu_y_list) > self.frame_length: self.x_list.pop(0) self.cpu_y_list.pop(0) self.memory_y_list.pop(0) self.cpu_graph.clear() self.cpu_graph.plot(self.x_list, self.cpu_y_list, "#117dbb") self.cpu_graph.set_title("CPU") self.cpu_graph.set_xlim(lower_limit, upper_limit) self.cpu_graph.fill_between(self.x_list, self.cpu_y_list, color="#f1f6fa") self.set_graph_style(self.cpu_graph) self.memory_graph.clear() self.memory_graph.plot(self.x_list, self.memory_y_list, "#117dbb") self.memory_graph.set_title("Memory") self.memory_graph.set_xlim(lower_limit, upper_limit) self.memory_graph.fill_between(self.x_list, self.memory_y_list, color="#f1f6fa") self.set_graph_style(self.memory_graph) # 计数器自增 self.counter += 1 def set_graph_style(self, graph): graph.grid() graph.set_yticklabels([]) graph.set_xticklabels([]) graph.set_ylim(0, 100) # 替换locator_params为MaxNLocator,强制设置8个整数刻度 graph.yaxis.set_major_locator(MaxNLocator(nbins=8, integer=True)) graph.spines["bottom"].set_color("#117dbb") graph.spines["left"].set_color("#117dbb") graph.spines["top"].set_visible(False) graph.spines["right"].set_visible(False) graph.margins(x=0) self.figure.tight_layout() if __name__ == "__main__": app = App() app.mainloop()
额外说明
- 自定义计数器彻底避免了
FuncAnimation初始调用的参数异常,确保X轴范围每次循环都正确更新,消除左侧空白; MaxNLocator支持强制指定刻度数量,不受轴范围自动调整的限制,integer=True保证刻度为整数,更符合CPU/内存百分比的显示需求;- 每次清除图表后重新调用
set_graph_style,确保两个图表的样式配置都能正确生效。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

