在 Python 中绘制串行数据如何暂停 matplotlib 图? [英] Plotting Serial data in Python how to pause matplotlib figure?

查看:46
本文介绍了在 Python 中绘制串行数据如何暂停 matplotlib 图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上我想暂停我在这里设置的实时绘图:

Basically I want to pause the live plot that I have setup here:

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"

我想暂停图中的绘图,但由于数据正在流动,我根本不知道如何处理该图.

I am wanting to pause the plot in the figure but I can't figure out how to work with the figure at all as the data is streaming.

推荐答案

因此,解决您的问题的一个好方法是使用线程来运行绘图窗口并通过主线程执行控制.这可以像这样实现:

So a good solution to your problem would be to use a thread to run the plotting window and have control performed through the main thread. This could be implemented like so:

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()

这应该给你一个命令行界面,如:

This should give you a command line interface like:

cmd >>>

以下任何语句应控制绘图仪的位置

Where any of the following statements should control the plotter

cmd >>>pause
cmd >>>unpause
cmd >>>stop

这篇关于在 Python 中绘制串行数据如何暂停 matplotlib 图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆