Как исправить FuncAnimation в matplotlib, который не работает в многопоточной среде? - PullRequest
0 голосов
/ 03 июля 2019

У меня есть код Python 2.7 с различными потоками, работающими параллельно. Поток с FuncAnimation для matplotlib просто показывает черный экран. Мне нужна помощь с исправлением размещения FuncAnimation в моем коде.

Я попытался вывести графическую функцию с FuncAnimation за пределы потока, и она отлично работает с рандомизированными данными. Более того, без FuncAnimation, используя простую команду plot, все работает, но это слишком медленно, поэтому я хотел использовать FuncAnimation в своем коде. runGraph (threadName, sleepTime) запускается один раз и вызывает updateG (frame) один раз.

import os
from time import sleep, strftime
from math import tan, pi
from threading import Thread
import matplotlib.pyplot as plt #1.55 SECONDS
from matplotlib.animation import FuncAnimation
import GPS_USB_Controller

graphX=[] 
graphY=[]
last_received = ''
cnt=0
frame=0
initial_y=0
initial_x=0
exitapp = False
GPS_USB_Controller.start_gps()
plt.ion()
Xper_last=0 
Yper_last=0
ix=0
iy=0

fig=0
ax=0
ln=0

cnt=0

fig,ax=plt.subplots(1,1)
ln, = plt.plot([], [], 'ro')
plt.show()


def GPS_fix():

    try:
        while (GPS_USB_Controller.gpsc.gpsd.fix.mode != 3):
            print "Waiting for GPS Fix.  GPS mode:",GPS_USB_Controller.gpsc.gpsd.fix.mode, "Satellites:", GPS_USB_Controller.gpsc.satellites
        #1 - no fix, 2 - 2D fix, 3 - 3D fix

    except KeyboardInterrupt:
        #print "GPS fix acquired."
        sleep(1)
        pass  

def zeroLevel():
    i=0
    global initial_x
    global initial_y
    global Xper_last
    global Yper_last
    buffer_string = ''    
    last_received = ''    

    while (i < 100):
        buffer_string = buffer_string + ser.read(ser.inWaiting())
        if '\n' in buffer_string:
            lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            buffer_string = lines[-1]
            ##print last_received         
        response = last_received
        if (response.count(";")) == 3: #Y; X; Heading; from IMU
            current_values=response.split(';')
            current_values.pop()           

            initial_x=tan(float(current_values[2])*(pi/180))*100 #convert degrees to radians to percent
            initial_y=tan(float(current_values[1])*(pi/180))*100

            Xper_last=initial_x
            Yper_last=initial_y  

            #print ("Initial X:" + str(initial_x) +", Initial Y: "+ str(initial_y))
            i=i+1 
            ##print i            
        else:
            print "Not all initialization data recieved - retrying"
    print "Level initialization complete"

GPS_fix ()

#Calibrate level
##print "Total Time", total
print "Enter the current percent cross slope (X)"
userX = input()
print "Enter the current percent running slope (Y)"
userY = input()
zeroLevel ()

def initG():
    global ax,fig,ln
    ax.set_xlim(-15,15)
    ax.set_ylim(-15, 15)
    return ln,
def runLevel(threadName, sleepTime):
    ser.flushInput() 
    global Xper
    global Yper
    global last_received
    global Xper_last
    global Yper_last
    Xper=initial_x
    Yper=initial_y
    buffer_string = ''  
    global ix
    global iy


    while not exitapp:
        sleep(sleepTime)
        buffer_string = buffer_string + ser.read(ser.inWaiting())
        if '\n' in buffer_string:
            lines = buffer_string.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            buffer_string = lines[-1]
            ##print last_received         

        response = last_received

        if (response.count(";")) == 3: #check if recieved time; Y; X; and Heading; from IMU-time removed
            current_values=response.split(';')
            current_values.pop()

            current_x=tan(float(current_values[2])*(pi/180))*100 #convert degrees to radians to percent
            current_y=tan(float(current_values[1])*(pi/180))*100

            Xper_actual=round((userX-initial_x)+current_x,2)
            Yper_actual=round((userY-initial_y)+current_y,2)
            Zper=round(float(current_values[0]),2)

            Xchange=abs(Xper_last-Xper_actual)
            Ychange=abs(Yper_last-Yper_actual)

            if (ix>4):
                Xper=Xper_actual
                ix=0
            elif (Xchange > 3):
                Xper=Xper_last
                ix=ix+1
            else:
                Xper=Xper_actual
                ix=0

            if (iy>4):
                Yper=Yper_actual
                iy=0                  
            elif (Ychange > 3):
                Yper=Yper_last
                iy=iy+1              
            else:
                Yper=Yper_actual    
                iy=0

            Xper_last=Xper
            Yper_last=Yper            

            matrixwritecommand([0x58]) #clear screen
            matrixwritecommand([0x47,1,1])
            ser_lcd.write("Cross:   "+str(Xper)+"%")#cross slope
            matrixwritecommand([0x47,1,2])
            ser_lcd.write("Running: "+str(Yper)+"%")#running slope
            database_stuff.log_data (GPS_USB_Controller.gpsc.fix.latitude, GPS_USB_Controller.gpsc.fix.longitude, Xper, Yper, Zper, "n/a", "n/a")            
        else:
            print "Data error"

def isnan(value):
    try:

        import math
        return math.isnan(float(value))
    except:

        return False

def updateG(frame):
    global Xper,Yper,graphX,graphY,cnt,isnan

    if(not isnan(Xper)):
        graphX.append(Xper) 
        graphY.append(Yper)  
    print("----------------")
    print(graphX)
    print(graphY)
    print("----------------")
    ln.set_data(graphX, graphY)
    if(cnt>=50):
        graphX.pop(0)                       
        graphY.pop(0)
        cnt=0
    return ln,

def runGraph(threadName, sleepTime):
    global fig,ax,ln,cnt,updateG,initG,Xper
    print("graph running")

    ani = FuncAnimation(fig, updateG, frames=int(Xper), init_func=initG, blit=True, interval=0)
    print(ani)
    plt.show()

def runGPS(threadName, sleepTime):
    while not exitapp:
        sleep(sleepTime)
        GPS_USB_Controller.print_gps()

if __name__ == '__main__':
    try:
        fig,ax=plt.subplots(1,1)
        ln, = plt.plot([], [], 'ro')
        plt.show()
        t1=Thread(target=runLevel, args=("Level", 0))
        t2=Thread(target=runGPS, args=("GPS", .5))
        t4=Thread(target=runGraph, args=("Graph", .5))
        t1.daemon=True
        t2.daemon=True
        t4.daemon=True
        t1.start()
        t2.start()
        t4.start()
        while True:
            sleep(.5)

    except KeyboardInterrupt:  #Ctrl C or Ctrl D
        exitapp=True
        lcdflash()
        matrixwritecommand([0x47,1,1])
        ser_lcd.write("Cancelled       ")

    except:
        lcdflash()
        matrixwritecommand([0x47,1,1])
        ser_lcd.write("ERROR           ")
        exitapp=True
        raise

    finally:
        GPS_USB_Controller.gpsc.stopController()
        GPS_USB_Controller.gpsc.join()
        t1.join()
        t2.join()
        t4.join()
        database_stuff.create_csv()
        matrixwritecommand([0x47,1,2])
        ser_lcd.write("CSV File Created")
        matrixwritecommand([0x46])

Я не получаю ошибок или предупреждений, только в черном окне matplotlib, которое не должно иметь место. На экране matplotlib должен отображаться график в реальном времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...