簡體   English   中英

python 中的 matplotlib.animate 使用多處理

[英]matplotlib.animate in python using multiprocessing

我正在嘗試使用 python 進程為 plot 設置動畫,如下所示:

from multiprocessing import Process
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

process_enabled = 1;
print("Process enabled: ", process_enabled)

x = []
y = []
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)        

def start_animation():
                 
   # Set up plot to call animate() function periodically   
   ani = animation.FuncAnimation(fig, animate, fargs=(x, y), interval=1000)
   print("Called animate function")
   plt.show()   
   
# This function is called periodically from FuncAnimation
def animate(i, xs, ys):
    
   fx=[0.045,0.02,0.0,0.04,0.015,-0.01,0.015,0.045,0.035,0.01,
        0.055,0.04,0.02,0.025,0.0,-0.005,-0.005,-0.02,-0.05,-0.03] # fx values        
    
   # Add x and y to lists
   xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
   if(i<len(fx)):                     
      ys.append(fx[i])             

   # Draw x and y lists
   ax.clear()
   if(i<len(fx)):   
      ys_stacked = np.stack((np.array(ys),0.1+np.array(ys)),axis=1)
      ax.plot(xs, ys_stacked)
      
   print("Animating")      

   # Format plot
   if(i<len(fx)):
      plt.xticks(rotation=45, ha='right')
      plt.subplots_adjust(bottom=0.30)
      plt.title('Force/Torque Sensor Data')
      plt.ylabel('Fx (N)')    

if(process_enabled):
    
   p_graph = Process(name='Graph', target=start_animation)
   print("Created graph process")

   p_graph.start()
   print("Started graph process")           
   
else:   

   start_animation()

當我禁用該過程時, start_animation() function 工作正常,並顯示 plot 並開始 animation。 但是,當啟用該進程時,該進程將啟動,然后代碼在 print("Called animate function") 處中斷。 沒有 plot window 並且終端中沒有錯誤消息)。

我對 python 和 matplotlib 中的多處理都是新手。 任何方向將不勝感激。

干杯,托尼

我正在嘗試解決同樣的問題,但還沒有完全弄清楚。 但是,我想我可以就您的問題提供一些有用的評論。

首先,您有什么理由要在單獨的進程中處理 animation 嗎? 您的方法似乎在單個過程中運行良好。 為此,您需要解決許多問題。 如果您確實需要一個單獨的過程,那么以下可能會有用。

首先,您將無法在'graph'進程中使用全局變量,因為該進程不共享這些變量的相同實例(請參閱全局變量和 Python 多處理)。

您可以在進程之間共享 state,但這對於您想要共享的復雜對象(即plt.figure() )來說是困難的。 有關更多信息,請參閱multiprocessing參考 ( https://docs.python.org/3/library/multiprocessing.html#sharing-state-between-processes )

最后一個建議是pyplot界面。 這對於簡單的腳本和交互式數據分析很方便,但它混淆了很多重要的事情——比如在調用plt方法時知道你正在處理的圖形、軸等。

我使用自定義 class 提供了另一種面向對象的方法,它可以運行您的 animation(無需單獨的進程):

import sys
from multiprocessing import Process, Queue
import datetime as dt
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.backends.qt_compat import QtWidgets
import matplotlib.animation as animation

class StripChart(FigureCanvasQTAgg):
    def __init__(self):
        self.fig = Figure(figsize=(8,5), dpi=100)
        self.ax = self.fig.add_subplot(111)

        # hold a copy of our torque data
        self.fx = [0.045,0.02,0.0,0.04,0.015,-0.01,0.015,0.045,0.035,0.01,
                   0.055,0.04,0.02,0.025,0.0,-0.005,-0.005,-0.02,-0.05,-0.03]

        super().__init__(self.fig)

        # instantiate the data arrays
        self.xs = []
        self.ys = []

    def start_animation(self):
        print("starting animation")

        # set up the animation
        self.ani = animation.FuncAnimation(self.fig, self.animate, init_func=self.clear_frame,
                                           frames=100, interval=500, blit=False)

    def clear_frame(self):
        self.ax.clear()
        self.ax.plot([], [])


    def animate(self, i):
        print("animate frame")
        # get the current time
        t_now = dt.datetime.now()

        # update trace values
        self.xs.append(t_now.strftime("%H:%M:%S.%f"))
        self.ys.append(self.fx[i % len(self.fx)])

        # keep max len(self.fx) points
        if len(self.xs) > len(self.fx):
            self.xs.pop(0)
            self.ys.pop(0)

        self.ax.clear()
        self.ax.plot(self.xs, self.ys)

        # need to reapply format after clearing axes
        self.fig.autofmt_xdate(rotation=45)
        self.fig.subplots_adjust(bottom=0.30)
        self.ax.set_title('Force/Torque Sensor Data')
        self.ax.set_ylabel('Fx (N)')

if __name__=='__main__':
    # start a new qapplication
    qapp = QtWidgets.QApplication(sys.argv)

    # create our figure in the main process
    strip_chart = StripChart()

    strip_chart.show()
    strip_chart.start_animation()

    # start qt main loop
    qapp.exec()

本例中的注意事項:

  • 您需要在您的環境中安裝后端(即pip install pyqt5
  • 我在 animation 中添加了一個init_func ,您並不需要它,因為您可以在animate方法中調用self.ax.clear()
  • 如果您需要更好的 animation 性能,您可以使用blit=True但您需要修改clear_frameanimate方法以返回要更新的藝術家(請參閱https://jakevdp.ZBF21518181B514/B753243BIO4/blog/B75243 2012/08/18/matplotlib-animation-tutorial/了解更多信息)。 一個缺點是您將無法使用該方法更新軸標簽。
  • 我已將其設置為無限運行,直到您關閉 window

我假設您想在單獨的進程中運行 animation 的原因是更新圖形數據或繪制所有點涉及一些耗時/CPU 密集型任務。 也許您已將其嵌入到其他 UI 中?

我嘗試在單獨的進程中執行 animation,但您需要傳遞顯示的圖形實例。 正如我所提到的,這並不簡單,盡管似乎有辦法做到這一點( https://stackoverflow.com/a/57793267/13752965 )。 如果我找到可行的解決方案,我會更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM