Matplotlib pyplot线不是通过动画绘制的

时间:2016-06-19 16:13:32

标签: python matplotlib

出于某种原因,我没有在下面的代码中绘制任何线条。目标是将我通过序列返回的温度绘制成图形,将时间绘制在X上,将温度绘制在Y上。

$ python -c 'import matplotlib; import matplotlib.pyplot; print(matplotlib.backends.backend)'
TkAgg
$ python3 -c 'import matplotlib; import matplotlib.pyplot; print(matplotlib.backends.backend)'
Qt5Agg

串行数据:

['20.00', '24.00', '22.00', '22.19', '22.25']
['20.00', '24.00', '21.90', '22.19', '22.25']
['20.00', '24.00', '21.90', '22.12', '22.25']
['20.00', '24.00', '21.90', '22.12', '22.25']
['20.00', '24.10', '21.90', '22.19', '22.25']
['20.00', '24.10', '21.90', '22.19', '22.25']
['20.00', '24.10', '21.90', '22.19', '22.25']
['20.00', '24.20', '21.90', '22.19', '22.31']

代码:

import sys, serial, argparse
import datetime
import numpy as np
from time import sleep

import matplotlib.pyplot as plt 
import matplotlib.animation as animation
from matplotlib.dates import DateFormatter

class SerialReader:
    def __init__(self, port, baudrate, ys=4):
        self.ser = serial.Serial(port, baudrate)
        self.ax = []
        self.ays = {}
        for i in range(0, ys):
            self.ays[i] = []

    def read(self):
        line = self.ser.readline()
        data = line.decode("utf8").rstrip().split("\t")
        if not len(data)==len(self.ays):
            return False
        return data

    def update(self, frameNum, *args):
        try:
            from pprint import pprint

            values = self.read()
            # happens only ones due to boot
            if not values:
                values = self.read()

            pprint(values)
            data = [float(val) for val in values]
            self.ax.append(datetime.datetime.now())
            for i in self.ays:
                self.ays[i].append(data[i])

            i=0
            for a in args:
                a.set_data(self.ax, self.ays[i])
                i+=1
        except KeyboardInterrupt:
            print('exiting')
        return args

    def close(self):
        self.ser.flush()
        self.ser.close()    


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Temp reader")
    parser.add_argument('-p', '--port', dest='port', default="/dev/ttyUSB0")
    parser.add_argument('-b', '--baud', dest='baud', default=9600, type=int)

    args = parser.parse_args()
    port = args.port
    baudrate = args.baud

    amount = 5
    reader = SerialReader(port, baudrate, amount)

    fig, ax = plt.subplots()
    ax.autoscale_view()

    ax.fmt_xdata = DateFormatter('%H:%M:%S')    
    plt.xlabel("Time")
    plt.ylabel("Temperature")

    lines = []
    lines.append(ax.plot_date([], [], '-', label = 'DHT11')[0])
    lines.append(ax.plot_date([], [], '-', label = 'DHT22 #1')[0])
    lines.append(ax.plot_date([], [], '-', label = 'DHT22 #1')[0])
    lines.append(ax.plot_date([], [], '-', label = 'MCP9808 #1')[0])
    lines.append(ax.plot_date([], [], '-', label = 'MCP9808 #2')[0])

    ax.legend(lines, [l.get_label() for l in lines], loc=0)

    fig.autofmt_xdate()

    anim = animation.FuncAnimation(fig, reader.update, fargs=lines, blit=True, interval=4000)
    fig.autofmt_xdate()

    plt.show()
    reader.close()

1 个答案:

答案 0 :(得分:0)

下面的确有效,但远非漂亮... t.b.h.我现在不在乎,只是很高兴它的工作原理,让它留在那里。

import datetime
import argparse
import serial

import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter


class SerialReader(object):
    def __init__(self, port, baudrate):
        self.ser = serial.Serial(port, baudrate)

    def __iter__(self):
        return self

    def __next__(self):
        return self.next()

    def next(self):
        line = self.ser.readline()
        return [float(val) for val in line.decode("utf8").split("\t")]

    def loop(self):
        try:
            while True:
                yield self.next()
        except KeyboardInterrupt:
            self.close()
            raise StopIteration()

    def close(self):
        self.ser.flush()
        self.ser.close()


if __name__ == '__main__':
    # create parser
    parser = argparse.ArgumentParser(description="Temp reader")
    # add expected arguments
    parser.add_argument('-p', '--port', dest='port', default="/dev/ttyUSB0")
    parser.add_argument('-b', '--baud', dest='baud', default=9600, type=int)

    # parse args
    args = parser.parse_args()
    port = args.port
    baudrate = args.baud

    fig, ax = plt.subplots(1, 1)
    ax.set_ylim(15, 25)
    ax.hold(True)

    rw = SerialReader(port, baudrate)

    # to avoid incomplete line
    rw.next()
    y1, y2, y3, y4, y5 = rw.next()
    x = datetime.datetime.now()

    xfmt = DateFormatter('%H:%M:%S')
    ax.fmt_xdata = xfmt
    ax.xaxis.set_major_formatter(xfmt)
    ax.autoscale_view()

    plt.ion()
    plt.show(False)
    plt.draw()

    lines = [
        ax.plot_date(x, y1, '-', label='DHT11')[0],
        ax.plot_date(x, y2, '-', label='DHT22 #1')[0],
        ax.plot_date(x, y3, '-', label='DHT22 #2')[0],
        ax.plot_date(x, y4, '-', label='MCP9808 #1')[0],
        ax.plot_date(x, y5, '-', label='MCP9808 #2')[0]
    ]

    ax.legend(lines, [l.get_label() for l in lines], loc=0)

    xs = []
    ys1 = []
    ys2 = []
    ys3 = []
    ys4 = []
    ys5 = []

    for y1, y2, y3, y4, y5 in rw.loop():
        now = datetime.datetime.now()
        xs.append(now)
        ax.set_xlim([x, now])
        ys1.append(y1)
        ys2.append(y2)
        ys3.append(y3)
        ys4.append(y4)
        ys5.append(y5)

        ax.set_ylim([min(ys1+ys2+ys3+ys4+ys5)-1, max(ys1+ys2+ys3+ys4+ys5)+1])
        lines[0].set_data(xs, ys1)
        lines[1].set_data(xs, ys2)
        lines[2].set_data(xs, ys3)
        lines[3].set_data(xs, ys4)
        lines[4].set_data(xs, ys5)

        fig.autofmt_xdate()
        fig.canvas.draw()
        plt.show(False)

        # ttyUSB is slow
        plt.pause(4)

    plt.close(fig)