如何使用 FuncAnimation 使用 matplotlib 更新和动画多个图形? [英] how to use FuncAnimation to update and animate multiple figures with matplotlib?

查看:62
本文介绍了如何使用 FuncAnimation 使用 matplotlib 更新和动画多个图形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尝试创建一个程序来读取串行数据并更新多个图形(目前只有 1 个折线图和 2 个条形图,但可能更多).

Trying to create a program that reads serial data and updates multiple figures (1 line and 2 bar charts for now but could potentially be more).

现在使用3个单独的对FuncAnimation()的调用,但事实证明它确实很慢,这不好,因为将来我仍然需要选择添加更多的动画人物.

Using 3 separate calls to FuncAnimation() right now, but proving to be really slow which is not good as I still need the option of adding more animated figures in the future.

那么我怎样才能使它成为更新所有三个(可能更多)数字的单个 FuncAnimation(或类似的东西)?另外,我该怎么做才能加快速度?

So how can I make it a single FuncAnimation (or maybe something similar) that updates all three (potentially more) figures? Alternatively, what can I do to speed it up a bit?

#figure for current
amps = plt.figure(1)
ax1 = plt.subplot(xlim = (0,100), ylim = (0,500))
line, = ax1.plot([],[])
ax1.set_ylabel('Current (A)')

#figure for voltage
volts = plt.figure(2)
ax2 = plt.subplot()
rects1 = ax2.bar(ind1, voltV, width1)
ax2.grid(True)
ax2.set_ylim([0,6])
ax2.set_xlabel('Cell Number')
ax2.set_ylabel('Voltage (V)')
ax2.set_title('Real Time Voltage Data')
ax2.set_xticks(ind1)

#figure for temperature
temp = plt.figure(3)
ax3 = plt.subplot()
rects2 = ax3.bar(ind2, tempC, width2)
ax3.grid(True)
ax3.set_ylim([0,101])
ax3.set_xlabel('Sensor Number')
ax3.set_ylabel('temperature (C)')
ax3.set_title('Real Time Temperature Data')
ax3.set_xticks(ind2)

def updateAmps(frameNum):

    try:
    #error check for bad serial data
        serialString = serialData.readline()
        serialLine = [float(val) for val in serialString.split()]
        print (serialLine)

        if (len(serialLine) == 5):
            voltV[int(serialLine[1])] = serialLine[2]
            tempC[int(serialLine[3])] = serialLine[4]
            currentA.append(serialLine[0])
            if (len(currentA)>100):
                currentA.popleft()

        line.set_data(range(100), currentA)

    except ValueError as e:
    #graphs not updated for bad serial data
        print (e)

    return line,

#function to update real-time voltage data
def updateVolts(frameNum):

    for rects, h in zip(rects1,voltV):
        rects.set_height(h)

    return rects1

#function to update real-time temperature data
def updateTemp(frameNum):

    for rects, h in zip(rects2,tempC):
        rects.set_height(h)

    return rects2

调用funcAnimation:

Call to funcAnimation:

anim1 = animation.FuncAnimation(amps, updateAmps,
                                interval = 20, blit = True)
anim2 = animation.FuncAnimation(volts, updateVolts, interval = 25, blit = True)
anim3 = animation.FuncAnimation(temp, updateTemp, interval = 30, blit = True)

推荐答案

回应@ImportanceOfBeingErnest 的评论,显而易见的解决方案是使用 3 个子图和仅一个 FuncAnimation() 调用.您只需确保您的回调函数返回所有艺术家的列表,即可在每次迭代时对其进行更新.

Echoing @ImportanceOfBeingErnest's comment, the obvious solution would be to use 3 subplots and only one FuncAnimation() call. You simply have to make sure your callback function returns a list of ALL artists to be updated at each iteration.

一个缺点是,更新将在所有3个子图中以相同的时间间隔进行(与您在示例中使用的不同时间相反).您可以通过使用全局变量来计算函数被调用的次数,并且只每隔一段时间执行一些绘图,例如,来解决这个问题.

One drawback is that the update will happen a the same interval in all 3 subplots (contrary to the different timings you had in your example). You could potentially work around that by using global variables that count how many time the function has been called and only do some of the plots every so often for example.

#figure 
fig = plt.figure(1)
# subplot for current
ax1 = fig.add_subplot(131, xlim = (0,100), ylim = (0,500))
line, = ax1.plot([],[])
ax1.set_ylabel('Current (A)')

#subplot for voltage
ax2 = fig.add_subplot(132)
rects1 = ax2.bar(ind1, voltV, width1)
ax2.grid(True)
ax2.set_ylim([0,6])
ax2.set_xlabel('Cell Number')
ax2.set_ylabel('Voltage (V)')
ax2.set_title('Real Time Voltage Data')
ax2.set_xticks(ind1)

#subplot for temperature
ax3 = fig.add_subplot(133)
rects2 = ax3.bar(ind2, tempC, width2)
ax3.grid(True)
ax3.set_ylim([0,101])
ax3.set_xlabel('Sensor Number')
ax3.set_ylabel('temperature (C)')
ax3.set_title('Real Time Temperature Data')
ax3.set_xticks(ind2)

def updateAmps(frameNum):

    try:
    #error check for bad serial data
        serialString = serialData.readline()
        serialLine = [float(val) for val in serialString.split()]
        print (serialLine)

        if (len(serialLine) == 5):
            voltV[int(serialLine[1])] = serialLine[2]
            tempC[int(serialLine[3])] = serialLine[4]
            currentA.append(serialLine[0])
            if (len(currentA)>100):
                currentA.popleft()

        line.set_data(range(100), currentA)

    except ValueError as e:
    #graphs not updated for bad serial data
        print (e)

    return line,

#function to update real-time voltage data
def updateVolts(frameNum):

    for rects, h in zip(rects1,voltV):
        rects.set_height(h)

    return rects1

#function to update real-time temperature data
def updateTemp(frameNum):

    for rects, h in zip(rects2,tempC):
        rects.set_height(h)

    return rects2

def updateALL(frameNum):
    a = updateAmps(frameNum)
    b = updateVolts(frameNum)
    c = updateTemp(frameNum)
    return a+b+c

animALL = animation.FuncAnimation(fig, updateALL,
                                interval = 20, blit = True)

这篇关于如何使用 FuncAnimation 使用 matplotlib 更新和动画多个图形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆