2014-03-19 94 views
0

基本上我想暫停實時情節我所建立的位置:在Python中繪製串行數據如何暫停matplotlib圖?

import serial 
import numpy as np 
from matplotlib import pyplot as plt 
ser = serial.Serial('/dev/tty.usbmodemfa131', 9600) 


#Setting up the animated plot 
plt.ion() # set plot to animated 
fig = plt.figure() 

ydata = [0] * 100 
ax1=plt.axes() 

# make plot 
line, = plt.plot(ydata) 
plt.ylim([24,29]) 

#Starting data collection 
while True: 
    rawData = ser.readline().rstrip() 
    x = len(rawData) 
    #print(floatData) 
    if len(rawData) <= 6: 
     try: 
      data = float(rawData) 
      if data <= 100: 
       ydata.append(data) 
       del ydata[0] 
       line.set_xdata(np.arange(len(ydata))) 
       line.set_ydata(ydata) # update the data 
       plt.draw() # update the plot 
     except ValueError: 
      print "Not a float" 

我想暫停在圖中的情節,但我無法弄清楚如何與這個數字在所有的工作作爲數據是流媒體。

+0

線程。如果在線程中設置了串行繪圖循環,並將一些if語句鉤子放入while循環中,則可以從另一個線程控制它,該線程在進入while循環時不會凍結。 – ebarr

回答

2

所以一個很好的解決方案就是使用一個線程來運行繪圖窗口並通過主線程執行控制。實現這一點的,像這樣:

import serial 
import numpy as np 
from matplotlib import pyplot as plt 
from threading import Thread,Event 
import time 

#A simple ring buffer to keep the plotting data in 
class RingBuffer(object): 
    def __init__(self,size): 
     self.size = size 
     self._size = 2*size 
     self._buffer = np.zeros(self._size) 
     self._idx = 0 

    def insert(self,val): 
     idx = self._idx%self.size 
     self._buffer[idx] = val 
     self._buffer[idx+self.size] = val 
     self._idx+=1 
     if self._idx > self.size: 
      self._idx-=self.size 

    def get(self): 
     start_idx = (self._idx)%self.size 
     end_idx = start_idx+self.size 
     return self._buffer[start_idx:end_idx] 

#A thread to handle plotting and reading data from the serial port 
class Plotter(Thread): 
    def __init__(self,stream,stop,pause): 
     Thread.__init__(self) 
     self.stream = stream 
     self.fig = plt.figure() 
     self.ax = plt.axes() 
     self.size = 100 
     self.xdata = np.arange(self.size) 
     self.ydata = RingBuffer(self.size) 
     self.line, = self.ax.plot(self.ydata.get()) 
     plt.ylim([24,29])             
     self.stop = stop 
    self.pause = pause 

    #The main loop of the thread, invoked with .start() 
    def run(self): 
     while not self.stop.is_set(): 
      if self.pause.is_set(): 
       continue 
      raw_data = self.stream.readline().rstrip()      
      if len(raw_data) <= 6: 
       try: 
        data = float(raw_data) 
       except ValueError: 
        print "Not a float" 
       else: 
        if data <= 100: 
         self.ydata.insert(data) 
         self.line.set_xdata(self.xdata) 
         self.line.set_ydata(self.ydata.get()) 
         plt.draw() 

      #sleep statement to reduce processor load 
     time.sleep(1) 

#this is implemented to facilitate use through something like Ipython easily 
class Controller(object): 
    def __init__(self): 

     #These events control execution of the thread main loop 
     self.stop = Event() 
     self.pause = Event() 
     self.stream = serial.Serial('/dev/tty.usbmodemfa131', 9600) 
     self.plotter_thread = Plotter(self.stream,self.stop,self.pause) 
     self.plotter_thread.start() 

def main(): 
    con = Controller() 

    #Loop over terminal input 
    #possible commands are stop, pause and unpause 
    while True: 
     command = raw_input("cmd >>>") 
     if command == "stop": 
      con.stop.set() 
      con.plotter_thread.join() 
      break 
     elif command == "pause": 
      con.pause.set() 
     elif command == "unpause": 
      con.pause.clear() 
     else: 
      print "unrecognised command" 

if __name__ == "__main__": 
    main() 

這應該給你像一個命令行界面:

cmd >>> 

凡下面的語句應控制繪圖儀

cmd >>>pause 
cmd >>>unpause 
cmd >>>stop 
+0

非常感謝這樣的迴應!因爲在我仍然試圖理解你的代碼之前,我還沒有處理線程。當我運行你在這裏的時候,我沒有一個數字出現。我想我會閱讀關於線程,並嘗試看看我是否缺少明顯的東西。再次感謝! –

+0

在一些matplotlib版本中,我認爲你可能需要做一個'plt.ion()'和/或'plt.show()'。當我運行這個時,我得到的陰謀窗口很好。這個問題揭示了這一點:http://stackoverflow.com/questions/5541594/matplotlib-draw-showing-nothing – ebarr

+0

嗯,這聽起來很有趣,但不能讓它顯示任何東西,即使我打開交互模式。 如果我在'Plotter'定義中包含'plt.show()',我會得到一個數字,但是沒有顯示數據。 – DrD