1

我刚刚开始学习 python 来绘制实时图形。我已经尝试过 stackoverflow 上提供的解决方案,但它们都不起作用。下面是我的代码,它不工作。请帮忙

import numpy as np
import matplotlib.pyplot as plt
import pyautogui as pg
from matplotlib.animation import FuncAnimation

%matplotlib notebook

binSize = 512
# fig(ax1,ax2) = plt.subplots(2,figsize=(12,6))
f = []
def animate(i):
    try:
        while True:
            x, y = pg.position()
            f.append(x)
    except KeyboardInterrupt:
           print('') 
#     f.append(15) 
    if len(f)<binSize :
        plt.cla()
        plt.plot(f, color='c',LineWidth=1.5,label="Noisy") 
    else:
        plt.cla()
        plt.plot(f[-binSize:],color='c',LineWidth=1.5,label="Noisy")
ani = FuncAnimation(plt.gcf(),animate,interval=1);

所以我更新了代码并尝试绘制两个子图,但过了一段时间

  1. 上图停止清除画布(鼠标 X 坐标)
  2. 下图停止更新绘图 (FFT)
  3. 当数据超过 binSize 时,笔记本冻结并且绘图更新非常缓慢


    %matplotlib notebook
    
    binSize = 256
    # fig(ax1,ax2) = plt.subplots(2,figsize=(12,6))
    f = []
    t = 0
    dt = 1
    fig,axs = plt.subplots(2,1) 
    
    def animate(i):
        x, y = pg.position() 
        f.append(x) 
        n = len(f)
        if n<binSize : 
            plt.sca(axs[0])
            plt.cla()
            plt.plot(f, color='c',LineWidth=1.5,label="MOUSE") 
        else:
            fhat = np.fft.fft(f,binSize)
            PSD = fhat*np.conj(fhat)/binSize
            freq  = (1/(dt*binSize))*np.arange(binSize)
            L = np.arange(1,np.floor(binSize/2),dtype='int')
            
            # update the code third time
      
               
            axs[0].clear() 
            axs[0].plot(f[-binSize:], color='c',LineWidth=1.5,label="MOUSE") 
#           axs[0].xlim(0,binSize) # this stopped the FFT graph to be plotted
        
#           plt.cla()
            axs[1].clear()  
            axs[1].plot(freq[L],PSD[L],color='r',LineWidth=2,label="FFT")  
    #         plt.xlim(t[0],t[-1])
    #         plt.legend()
    
    #         plt.sca(axs[1])
    #         plt.plot(freq[L],PSD[L],color='c',LineWidth=2,label="Mouse FFT") 
    #         plt.xlim(0,300)
    #         plt.legend()
    #         plt.cla()
    #         plt.plot(f[-binSize:],color='c',LineWidth=1.5,label="Mouse")
            
    ani = FuncAnimation(plt.gcf(),animate,interval=dt)  
4

2 回答 2

2

为了使其更快,您可以像其他答案一样减少数据

f.pop(0)

我还使用不同的方法来更新在我的计算机上运行得更快的绘图。

我在开始时创建空图

# needs `,` to get first element from list
p1, = axs[0].plot([], [], color='c', LineWidth=1.5, label="MOUSE")
p2, = axs[1].plot([], [], color='r', LineWidth=2,   label="FFT")

以后只更新绘图中的数据,而clear()不再plot()重复

        xdata = range(len(f))
        ydata = f
        p1.set_data(xdata, ydata)

        # replace data in plot
        xdata = range(binSize)
        ydata = f[-binSize:]
        p1.set_data(xdata, ydata)
        #p1.set_xdata(xdata)
        #p1.set_ydata(ydata)

        # replace data in plot
        xdata = freq[:(binSize//2)]
        ydata = PSD[:(binSize//2)]
        p2.set_data(xdata, ydata)

它只需要运行重新缩放绘图的代码

    # rescale view
    axs[0].relim()
    axs[0].autoscale_view(True,True,True)
    axs[1].relim()
    axs[1].autoscale_view(True,True,True)

animate()还必须返回新的地块

    # return plots
    return p1, p2

并且FuncAnimation()必须对他们进行攻击

ani = FuncAnimation(..., blit=True)

编辑:

动画工作得更快,因为我正常运行它python script.py,而不是在 Jupuyter Notebook

编辑:

当我正常运行时,我发现了一个可以找到解决方案的问题:它不会更新轴上的值/刻度。Jupyter Notebook没有这个问题。


import numpy as np
import matplotlib.pyplot as plt
import pyautogui as pg
from matplotlib.animation import FuncAnimation

%matplotlib notebook

binSize = 256

f = []
t = 0
dt = 1
fig, axs = plt.subplots(2, 1) 

# needs `,` to get first element from list
p1, = axs[0].plot([], [], color='c', LineWidth=1.5, label="MOUSE")
p2, = axs[1].plot([], [], color='r', LineWidth=2,   label="FFT")

freq = np.arange(binSize)/(dt*binSize)

def animate(i):
    x, y = pg.position() 
    n = len(f)

    if n < binSize :  
        f.append(x)

        # replace data in plot        
        xdata = range(len(f))
        ydata = f
        p1.set_data(xdata, ydata)
        #p1.set_xdata(xdata)
        #p1.set_ydata(ydata)
    else:
        f.pop(0)
        f.append(x)
        
        fhat = np.fft.fft(f, binSize)
        PSD  = fhat * np.conj(fhat) / binSize
        
        # replace data in plot
        #xdata = range(binSize)
        ydata = f[-binSize:]
        #p1.set_data(xdata, ydata)
        #p1.set_xdata(xdata)
        p1.set_ydata(ydata)

        # replace data in plot
        xdata = freq[:(binSize//2)]
        ydata = PSD[:(binSize//2)]
        p2.set_data(xdata, ydata)

    # rescale view
    axs[0].relim()
    axs[0].autoscale_view(True,True,True)
    axs[1].relim()
    axs[1].autoscale_view(True,True,True)
        
    # return plots
    return p1, p2

ani = FuncAnimation(plt.gcf(), animate, interval=dt, blit=True)

plt.show()
于 2020-06-30T01:56:16.707 回答
1

你应该试试这个。而不是清除 plt clear axs[0] 等等。此外,不是在 plt.plot 上绘图,而是在 axs[0].plot 上绘图

%matplotlib notebook

binSize = 256
# fig(ax1,ax2) = plt.subplots(2,figsize=(12,6))
f = []
t = 0
dt = 1
fig,axs = plt.subplots(2,1) 
plt.sca(axs[0]) 
plt.sca(axs[1])

def animate(i):
    x, y = pg.position() 
    n = len(f)
    if n<binSize :  
        f.append(x*100) 
        axs[0].clear() 
        axs[0].plot(f, color='c',LineWidth=1.5,label="MOUSE") 
    else:
        f.pop(0)
        f.append(x) 
        fhat = np.fft.fft(f,binSize)
        PSD = fhat*np.conj(fhat)/binSize
        freq  = (1/(dt*binSize))*np.arange(binSize)
        L = np.arange(1,np.floor(binSize/2),dtype='int') # index array of  [1,2,3..... binsize/2] type int
        
        axs[0].clear() 
        axs[0].plot(f[-binSize:], color='c',LineWidth=1.5,label="MOUSE")  
        
        axs[1].clear()  
        axs[1].plot(freq[L],PSD[L],color='r',LineWidth=2,label="FFT")   
        
ani = FuncAnimation(plt.gcf(),animate,interval=dt) 
plt.show()
于 2020-06-30T00:23:57.283 回答