2017-04-12 925 views
2

我正在製作一個Python GUI,以取代我使用Arduino製作接口的舊的Matlab GUI。我需要GUI能夠以每秒20點的速度繪製傳入的arduino數據,而不會減慢速度,我只需要它繪製最近的100點。我一直在遇到很多麻煩,並希望我能夠在如何做到這一點上得到一些幫助。我還沒有很好的使用Python,所以我提前道歉,沒有最pythonic代碼和不完全理解事物。這是我迄今爲止所擁有的。 (我需要能夠操縱GUI上的按鈕,而它在運行的情況下,我需要停下來等等)如何使用Python和Tkinter實時更新多個子圖

import Tkinter 
import numpy as np 
import serial 
import time 
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg 
from matplotlib.figure import Figure 
from math import sin 

class App: 
    def __init__(self, master): 

     frame = Tkinter.Frame(master) 

     self.Max_press = Tkinter.StringVar() 
     self.Max_press.set("10") 
     self.Min_press = Tkinter.StringVar() 
     self.Min_press.set("0") 
     self.Cycle_per_minute = Tkinter.StringVar() 
     self.Cycle_per_minute.set("12") 
     self.Duration_cycle = Tkinter.StringVar() 
     self.Duration_cycle.set("1") 

     self.respiration = Tkinter.LabelFrame(frame, text="Respiration Testing", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.respiration.grid(row=0, column=0, padx=20, pady=20) 

     self.max_pressure = Tkinter.Label(self.respiration, text="Maximum Pressure (mmHg)") 
     self.max_pressure.grid(row=0, column=0, padx=5, pady=5) 

     self.Max_pressure = Tkinter.Entry(self.respiration,textvariable=self.Max_press) 
     self.Max_pressure.grid(row=1, column=0, padx=5, pady=5) 

     self.min_pressure = Tkinter.Label(self.respiration, text="Minimum Pressure (mmHg)") 
     self.min_pressure.grid(row=2, column=0, padx=5, pady=5) 

     self.Min_pressure = Tkinter.Entry(self.respiration, textvariable=self.Min_press) 
     self.Min_pressure.grid(row=3, column=0, padx=5, pady=5) 

     self.cycles_per_minute = Tkinter.Label(self.respiration, text="Cycles Per Minute") 
     self.cycles_per_minute.grid(row=4, column=0, padx=5, pady=5) 

     self.Cycles_per_minute = Tkinter.Entry(self.respiration,textvariable=self.Cycle_per_minute) 
     self.Cycles_per_minute.grid(row=5, column=0, padx=5, pady=5) 

     self.duration_of_test = Tkinter.Label(self.respiration, text="Duration (minutes)") 
     self.duration_of_test.grid(row=6, column=0, padx=5, pady=5) 

     self.Duration_of_test = Tkinter.Entry(self.respiration, textvariable=self.Duration_cycle) 
     self.Duration_of_test.grid(row=7, column=0, padx=5, pady=5) 

     self.run_respiration = Tkinter.Button(self.respiration, text="RUN RESPIRATION", command=self.getData) 
     self.run_respiration.grid(row=8, column=0, padx=5, pady=5) 

     self.burst = Tkinter.LabelFrame(frame, text="Burst Test", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.burst.grid(row=0, column=1, padx=20, pady=20) 

     self.burst_pressure = Tkinter.Button(self.burst, text="RUN BURST TEST") 
     self.burst_pressure.grid(row=0, column=0, padx=5, pady=5) 

     self.test_options = Tkinter.LabelFrame(frame, text="Test Options", borderwidth=10, relief=Tkinter.GROOVE, padx=10, pady=10) 
     self.test_options.grid(row=0, column=2, padx=20, pady=35) 

     self.stop = Tkinter.Button(self.test_options, text="STOP", bd=10, height=5, width=10) 
     self.stop.grid(row=0, column=0, padx=10, pady=25) 

     self.pause = Tkinter.Button(self.test_options, text="PAUSE", bd=10, height=5, width=10) 
     self.pause.grid(row=1, column=0, padx=10, pady=25) 

     self.reset = Tkinter.Button(self.test_options, text="RESET", bd=10, height=5, width=10) 
     self.reset.grid(row=2, column=0, padx=10, pady=25) 

     self.save = Tkinter.Button(self.test_options, text="SAVE", bd=10, height=5, width=10) 
     self.save.grid(row=3, column=0, padx=10, pady=25) 

     fig = Figure() 
     ax = fig.add_subplot(211) 
     fig1 = Figure() 
     ax1 = fig1.add_subplot(212) 
     self.line, = ax.plot([x/0.5 for x in range(20)]) 
     self.line, = ax1.plot([x/1 for x in range(20)]) 
     self.canvas = FigureCanvasTkAgg(fig,master=master) 
     self.canvas.show() 
     self.canvas = FigureCanvasTkAgg(fig1,master=master) 
     self.canvas.show() 
     self.canvas.get_tk_widget().grid(row=0, column=3, padx=20, pady=20) 
     frame.grid(row=0, column=0, padx=20, pady=20) 

    def getData(self): 
     press_max = float(self.Max_press.get()) 
     press_min = float(self.Min_press.get()) 
     duration = float(self.Duration_cycle.get())*60*20 
     cycle_time = float(self.Cycles_per_minute.get()) 
     self.makeSine(press_max, press_min, duration, cycle_time) 

    def makeSine(self, Press_max, Press_min, Duration, Cycle_time): 
     i = 0 
     x = [] 
     y = [] 
     amp = (Press_max - Press_min)/2 
     offset = amp + Press_min 
     spb = 60/Cycle_time 
     while (i < Duration + 1): 
      x.append(i) 
      sine = amp*np.sin((x[i]*(np.pi*4))/(2*spb)) + offset + 1 
      y.append(sine) 
      i = i + 1 

     self.readWrite(x,y, Duration) 

    def readWrite(self, x, y, Duration): 
     i = 0 
     arduinoData = serial.Serial('com5', 115200) 
     arduinoData.flushInput() 
     start = time.time() 
     while (i < Duration + 1): # While loop that loops forever 
      while (arduinoData.inWaiting()==0): 
       pass 
      arduinoString = arduinoData.readline() 
      dataArray = arduinoString #.split(',') 
      #temp = int(dataArray[0]) 
      temp = int(dataArray) 
      #P = int(dataArray[1]) 
      print temp #, P 
      i = i + 1 
     end = time.time() 
     print (end - start) 




root = Tkinter.Tk() 
app = App(root) 
root.mainloop() 
+0

【如何更新FigureCanvasTkAgg內容](http://stackoverflow.com/questions/12124350/how-to-update-the-contents-of-a-figurecanvastkagg) –

回答

1

下面是關於如何在動畫中使用的最後x個數據點的例子。

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 

from collections import deque 
from random import randint, randrange 

def get_data(): 
    '''returns a random amount of random integers''' 
    return [randrange(100) for _ in range(randint(20, 50))] 

points = 200 

xdata = np.linspace(-30, 0, points) # make the X x axis, in this case from -30 to 0 
ydata = deque([0]*points, maxlen=points) # initialize the y data with 0's 

fig = plt.figure() 
ax1 = fig.add_subplot(1,1,1) 
line, = ax1.plot(xdata, ydata, lw=2) 

def run(*args): 
    ydata.extend(get_data()) # get and add data 
    line.set_ydata(ydata) # plot new data 
    plt.ylim(min(ydata), max(ydata)) # set limits (use if the data may go off the screen) 

ani = animation.FuncAnimation(fig, run, interval=1000//20) # 20 Hz is 1000//20 ms interval 
plt.show() 
+0

感謝可能的複製你的答案我一直玩的代碼你發過來,我只是似乎無法得到它與串行讀取功能,只傳遞一個值,而不是在你的例子中的預生成列表,也只是越來越它通常是圖形有一種方法,只更新圖形的一點,而不需要regraph一切與圖形最大的問題是我得到的時候,我開始有很多點在屏幕上,我只需要讀取與功能其餘部分之間的時間低於50ms – emg184

+0

這隻會更新y數據(機智h一點或多點);它並沒有重塑一切。您可以在倒數第二行中設置間隔時間。如果你想每50ms更新一次,那麼設置'interval = 50'。 – Novel