How to run a function concurrently with matplotlib animation?

别说谁变了你拦得住时间么 提交于 2021-01-29 05:29:13

问题


I am building a GUI that takes in sensor data from the raspberry pi and displays it onto a window via matplotlib animation. The code works fine, except when being run on raspberry pi, the matplotlib animation takes some time to execute, which momentarily blocks the sensor reading GetCPM that I'm interested in. How can I make both these programs run simultaneously without one clogging the other, I've tried the multiprocessing library, but I can't seem to get it to work.

Note: The sensor data that I'm plotting does not have to have a high sample rate, its the sensor that I'm displaying on label that does.

Here is my code

import matplotlib
matplotlib.use("TkAgg")
import numpy as np 

import tkinter as tk
from tkinter import ttk
from tkinter import *

import math
import datetime as dt
import time
from collections import Counter
import random as rn

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import style
import matplotlib.pyplot as plt

import threading as td
import multiprocessing as mp
from multiprocessing import Process, Queue

style.use('seaborn')
limit = np.array([5])

# Initialize Pressure Figure 

fig1, ax1 = plt.subplots()
fig2, ax2 = plt.subplots()

x1, y1 = [], []
x2, y2 = [], []

TOT = []
CPM = 0


def GetValues(i, x, y, ax):

    volts2 = rn.uniform(3,6)

    x.append(dt.datetime.now().strftime('%H: %M: %S.%f'))
    y.append(float(volts2))

    x = x[-50:]
    y = y[-50:]

    ax.clear()
    ax.plot(x, y, linewidth=1, color= 'k')

    ax.fill_between(x, y, limit[0], where=(y > limit[0]), facecolor='forestgreen', alpha=0.7, interpolate=True)
    ax.fill_between(x, y, limit[0], where=(y < limit[0]), facecolor='darkred', alpha=0.7, interpolate=True)

    ax.set_xticklabels([])


def animate(i, x, y, ax):


    volts = rn.uniform(2,8)

    x.append(dt.datetime.now().strftime('%H: %M: %S.%f'))
    y.append(float(volts))

    x = x[-50:]
    y = y[-50:]

    ax.clear()
    ax.plot(x, y, linewidth=1, color= 'k')

    ax.fill_between(x, y, limit[0], where=(y > limit[0]), facecolor='forestgreen', alpha=0.7, interpolate=True)
    ax.fill_between(x, y, limit[0], where=(y < limit[0]), facecolor='darkred', alpha=0.7, interpolate=True)

    ax.set_xticklabels([])

def GetCPM():

    global TOT, CPM 

    temp = 1

        # Test Case

    if temp == True:
        TOT.append(True)
    else:
        TOT.append(False)

    TOT = TOT[-2750:]
    count = Counter(TOT)
    CPM = count[True]

    return CPM



class App(tk.Tk):

    def __init__(self, *args, **kwargs):

        tk.Tk.__init__(self, *args, **kwargs)

#   If you want to customize the icon of the tk window, only accepts .ico 
        #tk.Tk.iconbitmap(self, default="iconname.ico")
        tk.Tk.wm_title(self, "Pressure")

        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        
        container.grid_rowconfigure(0,weight=1)
        container.grid_columnconfigure(0,weight=1)

        self.frames = {}

        frame = GUI(container, self)
        self.frames[GUI] = frame
        frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(GUI)

    def show_frame(self,cont):

        frame = self.frames[cont]
        frame.tkraise()

        
class GUI(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)

        canvas1 = FigureCanvasTkAgg(fig1, self)
        canvas1.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        canvas2 = FigureCanvasTkAgg(fig2, self)
        canvas2.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        #Initialize label as self.

        lbl = tk.Label(self, font = ('Sans Serif', 40, 'bold'), 
                                background = 'purple', 
                                foreground = 'White') 
        lbl.place(relx=0.5, rely=0.5, anchor=CENTER)

        def update():
            ll = GetCPM()
            lbl.config(text = "CPM = {}".format(ll)) 
            print(dt.datetime.now().strftime('%H: %M: %S.%f'))
            lbl.after(20, update) 

        update()



# interval determines the speed at which data is recorded, 1000 = 1 second
if __name__ == '__main__':
    app = App()

    t1 = mp.Process(target=GetCPM)
    t1.start()
    t1.join()

    ani_1 = animation.FuncAnimation(fig1, animate, interval = 500, 
                                    fargs=(x1, y1, ax1))
    ani_2 = animation.FuncAnimation(fig2, GetValues, interval = 500, 
                                    fargs=(x2, y2, ax2))

    app.mainloop()

来源:https://stackoverflow.com/questions/65242745/how-to-run-a-function-concurrently-with-matplotlib-animation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!