基于Matplotlib实现强化学习电池充电动态折线图绘制
解决强化学习电池充电模拟的动态可视化问题
原代码存在两个核心问题导致渲染异常:
- 每次调用
_render_frame都新建Matplotlib图形和Pygame窗口,造成图形对象堆积、渲染重叠 - 帧率控制不合理,画面刷新过快无法看清细节
修正方案
把图形和窗口的初始化逻辑移到类的初始化方法中(仅执行一次),每次渲染时只更新数据而非重建整个图形:
第一步:在类的__init__中完成初始化
def __init__(self): # 你的其他初始化代码(比如total_timesteps、_p_max等) # ... # 初始化Pygame环境 pygame.init() self.window_size = (800, 600) self.screen = pygame.display.set_mode(self.window_size) pygame.display.set_caption('电池充电模拟可视化') self.clock = pygame.time.Clock() # 初始化Matplotlib图形(仅执行一次) self.fig, self.axes = plt.subplots(2, 1, figsize=(8, 6)) # 配置功率输出子图 self.ax_power = self.axes[0] self.ax_power.set_title('Power output') self.ax_power.set_xlabel('Time step') self.ax_power.set_ylabel('Power (kW)') self.ax_power.set_xlim(0, self.total_timesteps) self.ax_power.set_xticks(np.arange(0, self.total_timesteps, 2), minor=True) self.ax_power.set_ylim(0, self._p_max) self.ax_power.grid(True) self.power_plot = None # 存储功率图对象 # 配置SoE子图 self.ax_soe = self.axes[1] self.ax_soe.set_title('State of Energy') self.ax_soe.set_xlabel('Time step') self.ax_soe.set_ylabel('SoE (kWh)') self.ax_soe.set_xlim(0, self.total_timesteps) self.ax_soe.set_xticks(np.arange(0, self.total_timesteps, 2), minor=True) self.ax_soe.set_ylim(0, self._target_soe) self.ax_soe.grid(True) self.soe_plot = None # 存储SoE图对象 # 初始化Matplotlib画布 self.canvas = agg.FigureCanvasAgg(self.fig)
第二步:重写_render_frame方法
def _render_frame(self): # 处理Pygame窗口事件(防止假死) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() plt.close(self.fig) return False # 更新功率图:移除旧图→绘制新图 if self.power_plot: for element in self.power_plot: element.remove() self.power_plot = self.ax_power.stem(self._current_time_step, self._currnt_power) # 更新SoE图:移除旧图→绘制新图 if self.soe_plot: for element in self.soe_plot: element.remove() self.soe_plot = self.ax_soe.stem(self._current_time_step, self._agent_soe) # 刷新Matplotlib画布 self.canvas.draw() renderer = self.canvas.get_renderer() # 将Matplotlib渲染结果转为Pygame表面并显示 self.screen.fill((255, 255, 255)) raw_data = renderer.tostring_rgb() size = self.canvas.get_width_height() surf = pygame.image.fromstring(raw_data, size, "RGB") self.screen.blit(surf, (0, 0)) # 控制帧率:设为5帧/秒,可根据需要调整 self.clock.tick(5) pygame.display.flip() return True
额外优化建议
- 如果想展示连续变化的SOC趋势,把
stem换成plot即可,折线图更适合表现连续更新的状态 - 若不需要Pygame窗口,直接用Matplotlib的
animation模块更轻量,比如FuncAnimation可以直接实现动态更新
内容的提问来源于stack exchange,提问作者nkp
相关产品推荐
相关产品推荐

