查看: 123|回复: 3

Python动态图表实战:FuncAnimation实时监控与阈值告警

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
动态图表在办公自动化中常用于跟踪持续变化的数据,如工单增长、性能指标。核心原理是在同一个画布上循环刷新数据,而非重新生成图片。本文基于Python的Matplotlib和FuncAnimation,实现从随机模拟到真实CSV/Excel数据源的动态折线图,并加入移动平均和阈值告警,让图表具备监控能力。
  1. import random
  2. import time
  3. from collections import deque
  4. import matplotlib.pyplot as plt
  5. from matplotlib.animation import FuncAnimation
  6. plt.rcParams["font.sans-serif"] = ["SimHei"]
  7. plt.rcParams["axes.unicode_minus"] = False
  8. MAX_POINTS = 60
  9. x_data = deque(maxlen=MAX_POINTS)
  10. y_data = deque(maxlen=MAX_POINTS)
  11. start_time = time.time()
  12. fig, ax = plt.subplots(figsize=(10, 5))
  13. (line,) = ax.plot([], [], marker="o", linewidth=2)
  14. ax.set_title("动态折线图:实时数据更新")
  15. ax.set_xlabel("时间(秒)")
  16. ax.set_ylabel("指标值")
  17. ax.grid(True, linestyle="--", alpha=0.35)
  18. def get_latest_value():
  19.     return random.randint(50, 150)
  20. def update(frame):
  21.     current_time = int(time.time() - start_time)
  22.     current_value = get_latest_value()
  23.     x_data.append(current_time)
  24.     y_data.append(current_value)
  25.     line.set_data(list(x_data), list(y_data))
  26.     ax.set_xlim(max(0, current_time - MAX_POINTS), current_time + 1)
  27.     ax.set_ylim(min(y_data) - 5, max(y_data) + 5)
  28.     return (line,)
  29. ani = FuncAnimation(fig, update, interval=1000, blit=True)
  30. plt.tight_layout()
  31. plt.show()
复制代码

以上代码演示了最小可用版:用deque限制缓存长度(60个点),避免数据无限增长导致卡顿。实际使用时只需替换get_latest_value()为读取文件、API或系统指标的代码。

接下来加入移动平均和阈值告警,使图表具备业务判断能力。
  1. import random, time
  2. from collections import deque
  3. import matplotlib.pyplot as plt
  4. from matplotlib.animation import FuncAnimation
  5. plt.rcParams["font.sans-serif"] = ["SimHei"]
  6. plt.rcParams["axes.unicode_minus"] = False
  7. MAX_POINTS = 60
  8. WINDOW = 8
  9. THRESHOLD = 140
  10. x_data = deque(maxlen=MAX_POINTS)
  11. y_data = deque(maxlen=MAX_POINTS)
  12. ma_data = deque(maxlen=MAX_POINTS)
  13. start_time = time.time()
  14. fig, ax = plt.subplots(figsize=(10,5))
  15. (line,) = ax.plot([],[], marker="o", linewidth=2, label="实时值")
  16. (ma_line,) = ax.plot([],[], linestyle="--", linewidth=2, label="移动平均")
  17. (th_line,) = ax.plot([],[], linestyle=":", linewidth=2, label="阈值线")
  18. ax.set_title("动态图表:实时值 + 移动平均 + 阈值线")
  19. ax.set_xlabel("时间(秒)")
  20. ax.set_ylabel("指标值")
  21. ax.grid(True, linestyle="--", alpha=0.35)
  22. ax.legend(loc="upper left")
  23. def get_latest_value():
  24.     base = random.randint(80,130)
  25.     if random.random() < 0.08:
  26.         base += random.randint(10,40)
  27.     return base
  28. def moving_average(values, window):
  29.     values = list(values)
  30.     if len(values) < window:
  31.         return sum(values)/len(values)
  32.     return sum(values[-window:])/window
  33. def update(frame):
  34.     current_time = int(time.time() - start_time)
  35.     current_value = get_latest_value()
  36.     x_data.append(current_time)
  37.     y_data.append(current_value)
  38.     ma_data.append(moving_average(y_data, WINDOW))
  39.     line.set_data(list(x_data), list(y_data))
  40.     ma_line.set_data(list(x_data), list(ma_data))
  41.     if x_data:
  42.         th_line.set_data([x_data[0], x_data[-1]], [THRESHOLD, THRESHOLD])
  43.     ax.set_xlim(max(0, current_time - MAX_POINTS), current_time + 1)
  44.     ax.set_ylim(min(min(y_data), THRESHOLD)-10, max(max(y_data), THRESHOLD)+10)
  45.     if current_value >= THRESHOLD:
  46.         ax.set_title(f"触发阈值告警:当前值={current_value}")
  47.     else:
  48.         ax.set_title("动态图表:实时值 + 移动平均 + 阈值线")
  49.     return (line, ma_line, th_line)
  50. ani = FuncAnimation(fig, update, interval=1000, blit=True)
  51. plt.tight_layout()
  52. plt.show()
复制代码

该版本中,移动平均线使趋势更平滑,阈值线(140)触发时标题自动显示告警。阈值需根据业务数据合理设定,例如CPU使用率、服务响应时间等。

在真实办公场景中,数据往往来自Excel或CSV文件。以下代码演示轮询读取CSV并刷新图表,适合轻量监控部署:
  1. import time
  2. from collections import deque
  3. from pathlib import Path
  4. import pandas as pd
  5. import matplotlib.pyplot as plt
  6. from matplotlib.animation import FuncAnimation
  7. plt.rcParams["font.sans-serif"] = ["SimHei"]
  8. plt.rcParams["axes.unicode_minus"] = False
  9. CSV_PATH = Path("metrics.csv")
  10. MAX_POINTS = 120
  11. x_data = deque(maxlen=MAX_POINTS)
  12. y_data = deque(maxlen=MAX_POINTS)
  13. fig, ax = plt.subplots(figsize=(10,5))
  14. (line,) = ax.plot([],[], marker="o", linewidth=2)
  15. ax.set_title("动态更新:轮询读取CSV最新数据")
  16. ax.set_xlabel("时间")
  17. ax.set_ylabel("指标值")
  18. ax.grid(True, linestyle="--", alpha=0.35)
  19. def read_latest_from_csv():
  20.     if not CSV_PATH.exists():
  21.         return None, None
  22.     df = pd.read_csv(CSV_PATH)
  23.     if df.empty:
  24.         return None, None
  25.     last = df.iloc[-1]
  26.     return str(last["timestamp"]), float(last["value"])
  27. def update(frame):
  28.     timestamp, value = read_latest_from_csv()
  29.     if timestamp is None:
  30.         return (line,)
  31.     # 避免重复追加同一时间戳
  32.     if len(x_data) > 0 and x_data[-1] == timestamp:
  33.         return (line,)
  34.     x_data.append(timestamp)
  35.     y_data.append(value)
  36.     line.set_data(list(range(len(x_data))), list(y_data))
  37.     ax.set_xlim(0, max(10, len(x_data)))
  38.     ax.set_ylim(min(y_data)-5, max(y_data)+5)
  39.     # 设置时间标签并旋转
  40.     ax.set_xticks(range(len(x_data)))
  41.     ax.set_xticklabels(list(x_data), rotation=30, ha="right")
  42.     return (line,)
  43. ani = FuncAnimation(fig, update, interval=2000, blit=True)
  44. plt.tight_layout()
  45. plt.show()
复制代码

注意:CSV文件被其他程序写入时可能出现读取冲突。建议在脚本中加入异常捕获,判断重复时间戳和空数据。正式环境可优先使用CSV作为中间文件,避免直接读写xlsx导致的占用风险。

动态图表的交付方式有三种:本地窗口展示(调试/演示)、导出GIF(博客/复盘)、Web看板(团队共享)。导出GIF示例:
  1. pip install pillow
  2. ani.save("动态图表.gif", writer="pillow", fps=2)
复制代码

需要验证的要点:数据源更新后图表追加新点;无更新时不重复;y轴范围覆盖最新值;移动平均跟随变化;阈值告警正确触发。常见问题包括中文乱码(配置SimHei字体)、动画越来越卡(用deque限制点数)、CSV不刷新(检查文件是否写入新行)、blit=True异常(可改为False调试)。

总之,动态图表的核心链路为:数据源 → 刷新机制 → 图表对象 → 分析规则 → 交付方式。建议学习顺序:先用随机数跑通FuncAnimation,再加入移动平均和阈值,然后替换成真实CSV/Excel,最后考虑导出GIF或制作Web看板。
回复

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python动态图表实战:FuncAnimation实时监控与阈值告警

感谢分享!这代码很实用,直接把动态图表从演示拉到了准生产级监控的水平。`deque`限制缓存长度、移动平均平滑数据、阈值线告警,这些组合在办公自动化和运维场景下非常经典。我有个小疑问:如果想改成从真实CSV文件读取新行来更新图表,大概需要怎么改造`get_latest_value()`函数?比如用文件指针跟踪末行位置?
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python动态图表实战:FuncAnimation实时监控与阈值告警

非常感谢楼主分享这么详细的实战代码!deque 限制缓存长度避免卡顿的思路很实用,移动平均加阈值线的设计让动态图表真正具备了监控价值。想请教一下:当真实数据源的读取可能比 1 秒慢(比如需要解析大文件或请求网络 API)时,FuncAnimation 的 interval 参数和 update 函数的执行时间有没有什么经验上的平衡建议?另外,阈值告警除了画虚线,是否考虑过在值超过阈值时触发颜色变化或弹出提示?期待楼主的更多分享。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python动态图表实战:FuncAnimation实时监控与阈值告警

感谢楼主的分享,非常实用的动态图表实战案例。用 `deque` 限制缓存长度避免内存泄漏,以及通过 `FuncAnimation` 实现无阻塞刷新,这些细节都考虑得很到位。特别是第二段代码加入了移动平均和阈值线,让图表具备了初级的监控告警能力,很适合日常办公中跟踪工单量、服务器负载等场景。 一个小想法:如果阈值线能用 `ax.axhline` 固定绘制(比如 `ax.axhline(y=THRESHOLD, linestyle=':')`),可能比用 `plot` 动态更新更简单,也能减少每次更新的数据量。另外,对于真实数据源(CSV/Excel),建议在 `get_latest_value` 内部加入异常处理,避免文件读取失败导致图表卡死。 期待楼主后续如果有其他接入API或数据库的扩展案例,也欢迎继续分享。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-15 13:40 , Processed in 0.025117 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部