使用 pyplot 进行实时绘图

王林
发布: 2024-09-03 17:17:02
原创
661 人浏览过

Real-time plotting with pyplot

我想绘制一些从简单的投票应用程序生成的数据的图表。我过去曾对 pyplot 进行过修改,但我没有尝试从头开始创建任何东西。幸运的是,它非常流行,并且在 StackOverflow 和其他地方可以找到大量示例。

我进行了搜索,并从这个与随时间更新图表相关的答案开始。

import matplotlib.pyplot as plt
import numpy as np

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma

for phase in np.linspace(0, 10*np.pi, 500):
    line1.set_ydata(np.sin(x + phase))
    fig.canvas.draw()
    fig.canvas.flush_events()
登录后复制

此代码动画正弦波变化阶段。

前两行导入我想要使用的库:matplotlib.pyplot 进行绘图和处理 GUI。

ion() 方法,如果我理解的话(尽管我可能不理解),使 pyplot 驱动 GUI。您还可以在 tkinter 程序中使用它,或者使用它来生成静态图像,但在我们的例子中,让它为我们处理图形的 GUI 是有意义的。 (这就是稍后调用的flush_events()正在做的事情:允许与图形窗口进行交互。)

此示例使用 numpy 方法 linspace() 来创建 x 值。它返回一个 numpy 数组,这是一个奇特的 Python 列表。

使用 np.sin 而不是 math.sin 的原因是广播。这是将函数应用于列表中每个项目的 numpy 术语。事实上,我突然想到,不用 numpy 使用 map 也可以实现同样的事情:

map(lambda n: math.sin(n), x)
登录后复制

但是numpy广播使用起来方便又简单。

现在是 pyplot 设置。首先,创建一个新的“图形”(图)。在此图中,添加一个子图(ax)——可能有很多。 111 有相当深奥的解释,“创建一个 1x1 网格,并将这个子图放在第一个单元格中。”

在这个子图(或一组轴)中,使用传递的 x 和 y 值绘制一条线。 (点用直线连接并连续绘制。)“r-”是指定红色实线的简写方式。我们可以指定多行,因此plot()返回一个元组;上面的代码使用元组解包来提取我们想要的一个值。

这是一个好的开始,但我需要随着时间的推移延长 x 轴。如果需要,此代码也不会更新 y 轴的边界 - 它被锁定到为第一个图计算的任何边界。更多的搜索让我找到了这个答案。引用他们的话:

您需要更新坐标区的 dataLim,然后根据 dataLim 更新坐标区的 viewLim。适当的方法是axes.relim()和ax.autoscale_view()方法。

当然,听起来不错。根据他们的示例,我创建了一个在 x 和 y 上都增长的演示图。

import matplotlib.pyplot as plt
import numpy as np
from threading import Thread
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Returns a tuple of line objects

growth = 0

while True:
    x.append(x_next_max / 10)
    x_next_max += 1
    line1.set_xdata(x)
    line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100))
    ax.relim()
    ax.autoscale()
    fig.canvas.draw()
    fig.canvas.flush_events()

    sleep(0.1)
登录后复制

现在我已经取得进展了。但是,这是一个阻塞循环,我需要偶尔更新我的数据。如果我有多个线程,我就必须担心更新变量时的线程安全问题。在这种情况下,我可以偷懒,因为我知道该变量仅每 5 分钟更新一次(或者无论轮询函数运行多久);变量在代码行中间不存在被覆盖的危险。

import matplotlib.pyplot as plt
import numpy as np
from threading import Timer
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Plot returns a tuple of line objects

growth = 0
new_x = None

dT = 1

def grow():
    global new_x, x_next_max
    while True:
        new_x = x + [x_next_max / 10]
        x_next_max += 1
        sleep(dT) # grow every dT seconds

t = Thread(target=grow)
t.start()

while True:

    if new_x:
        x = new_x
        new_x = None
        line1.set_xdata(x)
        line1.set_ydata(np.sin(x) + np.sin(np.divide(x, 100)) + np.divide(x, 100))
        ax.relim()
        ax.autoscale()
        fig.canvas.draw()

    fig.canvas.flush_events()

    sleep(0.1)
登录后复制

只有当增长线程为 new_x 赋值时,图表才会更新。请注意,flush_events() 调用位于“if”语句之外,因此它被频繁调用。

以上是使用 pyplot 进行实时绘图的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!