2013-10-29 17 views
9

So che ci sono abbastanza alcune domande sul matplotlib e filettatura, inoltre, che non è pyplot threadsave. Non ho trovato nulla su questo particolare problema comunque. Quello che voglio fare è: tracciare una figura e aggiornarla ogni secondo. Per questo ho voluto creare un filo, ma finora non ho potuto anche ottenere una trama vera e propria dal thread. Inoltre, mi sono bloccato con Qt4, quindi potrebbe essere altri backend si comportano differenti.Plotting con matplotlib in fili

Ecco un esempio molto semplice: Una trama è creato in plot_a_graph(). Funziona correttamente quando chiamato dal programma principale ma ritarda l'ulteriore esecuzione del codice principale. Tuttavia, quando viene chiamato da una discussione, non viene visualizzato alcun grafico.

import matplotlib 
matplotlib.use("qt4agg") 
import matplotlib.pyplot as plt 
import threading 
import time 

def plot_a_graph(): 
    f,a = plt.subplots(1) 
    line = plt.plot(range(10)) 
    plt.show() 
    print "plotted graph"  
    time.sleep(4) 


testthread = threading.Thread(target=plot_a_graph) 

plot_a_graph()  # this works fine, displays the graph and waits 
print "that took some time" 

testthread.start() # Thread starts, window is opened but no graph appears 
print "already there" 

Thx per voi aiuto

+1

Fare tutto il vostro tracciato sul thread principale. Almeno con QT, l'interfaccia grafica non piace se si tenta di fare questo. – tacaswell

risposta

8

Il mio suggerimento è quello di utilizzare il modulo python multiprocessing al posto del modulo threading. Sono stato in grado di eseguire solo lievi modifiche al codice di esempio e con successo scaricare l'matplotlib tramando per un processo figlio, mentre il flusso di controllo nel processo principale continua (vedi codice qui sotto).

Suggerisco di leggere la documentazione di multiprocessing o una qualsiasi quantità di post di blog sull'argomento, se si desidera che i processi figli comunichino indietro & avanti con il genitore nel contesto del flusso di controllo del codice più ampio (che non è completamente descritto nella tua domanda). Si noti che multielaborazione ha il vantaggio di elusione pitone global interpreter lock & consentendo di sfruttare in architetture di computer multi-core.

#a slight modification of your code using multiprocessing 
import matplotlib 
matplotlib.use("qt4agg") 
import matplotlib.pyplot as plt 
#import threading 
#let's try using multiprocessing instead of threading module: 
import multiprocessing 
import time 

#we'll keep the same plotting function, except for one change--I'm going to use the multiprocessing module to report the plotting of the graph from the child process (on another core): 
def plot_a_graph(): 
    f,a = plt.subplots(1) 
    line = plt.plot(range(10)) 
    print multiprocessing.current_process().name,"starting plot show process" #print statement preceded by true process name 
    plt.show() #I think the code in the child will stop here until the graph is closed 
    print multiprocessing.current_process().name,"plotted graph" #print statement preceded by true process name 
    time.sleep(4) 

#use the multiprocessing module to perform the plotting activity in another process (i.e., on another core): 
job_for_another_core = multiprocessing.Process(target=plot_a_graph,args=()) 
job_for_another_core.start() 

#the follow print statement will also be modified to demonstrate that it comes from the parent process, and should happen without substantial delay as another process performs the plotting operation: 
print multiprocessing.current_process().name, "The main process is continuing while another process deals with plotting." 
+0

thx! Purtroppo, ho provato prima, ciò che ottengo è un errore: ... PicklingError: Impossibile salamoia : Non è trovato come __main __ plot_a_graph. – Fabian

0

utilizzare un segnale di Qt per chiamare la funzione di tracciato nel thread principale

import matplotlib 
matplotlib.use("qt4agg") 
import matplotlib.pyplot as plt 
import threading 
import time 

from PyQt4 import QtCore 

class Call_in_QT_main_loop(QtCore.QObject): 
    signal = QtCore.pyqtSignal() 

    def __init__(self, func): 
     super().__init__() 
     self.func = func 
     self.args = list() 
     self.kwargs = dict() 
     self.signal.connect(self._target) 

    def _target(self): 
     self.func(*self.args, **self.kwargs) 

    def __call__(self, *args, **kwargs): 
     self.args = args 
     self.kwargs = kwargs 
     self.signal.emit() 

@Call_in_QT_main_loop 
def plot_a_graph(): 
    f,a = plt.subplots(1) 
    line = plt.plot(range(10)) 
    plt.show() 
    print("plotted graph") 
    print(threading.current_thread()) # print the thread that runs this code 

def worker(): 
    plot_a_graph() 
    print(threading.current_thread()) # print the thread that runs this code 
    time.sleep(4) 

testthread = threading.Thread(target=worker) 

testthread.start()