Matplotlib从文本文件定义数组

时间:2015-01-13 15:21:19

标签: matplotlib

所以我正在尝试弄清楚如何读取文本文件并从中绘制值...我有一个文本文件,每5秒更新一次,值写成如下:

"Day, Time, channel1, channel2, channel3, channel4"

每一行都是新的5秒数据标记。

我想绘制一条4行(channel1 - channel4)的动画图表 共享相同的x轴值...我该如何定义?以下是相关代码 到目前为止......

#MATPLOTLIB ANIMATED GRAPH
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)


ln1, = ax1.plot([], [], 'r-')
ln2, = ax1.plot([], [], 'g-')
ln3, = ax1.plot([], [], 'b-')
ln4, = ax1.plot([], [], 'p-')

def animate(i):
    pullData = open("%s.txt" % FILE_NAME,"r").read()
    dataArray = pullData.split('\n')
    xar = []
    yar = []
    for eachLine in dataArray:
        if len(eachLine)>1:
            x,y = eachLine.split(',')
            ln1.set_data(x1, y1)
            ln2.set_data(x1, y2)
            ln3.set_data(X1, y3)
            ln4.set_data(x1, y4)
    ax1.clear()
    ax1.plot(ln1)
    ax1.plot(ln2)
    ax1.plot(ln3)
    ax1.plot(ln4)
ani = animation.FuncAnimation(fig, animate, interval=5000)
plt.show()

我如何定义每条线的x和y?

------编辑#3 -----

import Queue
import datetime as DT
import collections
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing as mp
import time
import matplotlib.dates as mdates
import matplotlib.animation as animation
from ABE_DeltaSigmaPi import DeltaSigma 
from ABE_helpers import ABEHelpers

i2c_helper = ABEHelpers() 
bus = i2c_helper.get_smbus() 
adc = DeltaSigma(bus, 0x68, 0x69, 18)

#Rename file to date
base_dir = '/home/pi/Desktop/DATA'
filename_time = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d')
filename_base = os.path.join(base_dir, filename_time)
filename = '%s.txt' % filename_base

# you will want to change read_delay to 5000
read_delay = int(5000)    # in milliseconds 
write_delay = read_delay/1000.0  # in seconds 
window_size = 60
nlines = 8
datenums = collections.deque(maxlen=window_size)
ys = [collections.deque(maxlen=window_size) for i in range(nlines)]

def animate(i, queue):
    try:
        row = queue.get_nowait()
    except Queue.Empty:
        return
    datenums.append(mdates.date2num(row[0]))
    for i, y in enumerate(row[1:]):
        ys[i].append(y)
    for i, y in enumerate(ys):
        lines[i].set_data(datenums, y)
    ymin = min(min(y) for y in ys)
    ymax = max(max(y) for y in ys)
    xmin = min(datenums)
    xmax = max(datenums)
    if xmin < xmax:
        ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    fig.canvas.draw()

def write_data(filename, queue):
    while True:
        delay1 = DT.datetime.now()
        row = []
        for i in range(nlines):
            # read from adc channels and print to screen
            channel = adc.read_voltage(i)
            row.append(channel)

        queue.put([delay1]+row)

        #print voltage variables to local file
        with open(filename, 'a') as DAQrecording:
            time1 = delay1.strftime('%Y-%m-%d')
            time2 = delay1.strftime('%H:%M:%S')
            row = [time1, time2] + row
            row = map(str, row)
            DAQrecording.write('{}\n'.format(', '.join(row)))

        #Delay until next 5 second interval
        delay2 = DT.datetime.now()
        difference = (delay2 - delay1).total_seconds()
        time.sleep(write_delay - difference)

def main():
    global fig, ax, lines
    queue = mp.Queue()
    proc = mp.Process(target=write_data, args=(filename, queue))
    # terminate proc when main process ends
    proc.daemon = True
    # spawn the writer in a separate process
    proc.start()

    fig, ax = plt.subplots()
    xfmt = mdates.DateFormatter('%H:%M:%S')
    ax.xaxis.set_major_formatter(xfmt)
    # make matplotlib treat x-axis as times
    ax.xaxis_date()

    fig.autofmt_xdate(rotation=25)

    lines = []
    for i in range(nlines):
        line, = ax.plot([], [])
        lines.append(line)

    ani = animation.FuncAnimation(fig, animate, interval=read_delay, fargs=(queue,))
    plt.show()    

if __name__ == '__main__':
    main()

2 个答案:

答案 0 :(得分:1)

从同一文件中写入和读取将需要锁定以防止竞争条件 - 在文件完全写入之前从文件读取。这是可能的,但在下面我建议采用不同的方式。

由于两个程序都是用Python编写的,因此可以使用多处理模块生成编写器进程,并将其写入队列。 然后主进程可以animate从队列中获取值并绘制结果。队列为我们处理锁定和进程间通信,并允许我们将日期时间对象和浮点值作为Python对象传输,而不必从文件中读取它们并解析字符串。

import Queue
import datetime as DT
import collections
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing as mp
import time
import matplotlib.dates as mdates
import matplotlib.animation as animation
try:
    from ABE_DeltaSigmaPi import DeltaSigma 
    from ABE_helpers import ABEHelpers
    i2c_helper = ABEHelpers() 
    bus = i2c_helper.get_smbus() 
    adc = DeltaSigma(bus, 0x68, 0x69, 18)
except ImportError:
    class ADC(object):
        """
        This is a dummy class to mock the adc.read_voltage calls.
        """
        def __init__(self):
            self.x = 0
        def read_voltage(self, i):
            if i == 0:
                self.x += 0.1
            return np.sin(self.x/10)*(i+1)

    adc = ADC()

filename = 'data.txt'
# you will want to change read_delay to 5000
read_delay = int(0.05 * 1000)    # in milliseconds 
write_delay = read_delay/1000.0  # in seconds 
window_size = 60
nlines = 8
datenums = collections.deque(maxlen=window_size)
ys = [collections.deque(maxlen=window_size) for i in range(nlines)]

def animate(i, queue):
    try:
        row = queue.get_nowait()
    except Queue.Empty:
        return
    datenums.append(mdates.date2num(row[0]))
    for i, y in enumerate(row[1:]):
        ys[i].append(y)
    for i, y in enumerate(ys):
        lines[i].set_data(datenums, y)
    ymin = min(min(y) for y in ys)
    ymax = max(max(y) for y in ys)
    xmin = min(datenums)
    xmax = max(datenums)
    if xmin < xmax:
        ax.set_xlim(xmin, xmax)
    ax.set_ylim(ymin, ymax)
    fig.canvas.draw()

def write_data(filename, queue):
    while True:
        delay1 = DT.datetime.now()
        row = []
        for i in range(nlines):
            # read from adc channels and print to screen
            channel = adc.read_voltage(i)
            temp = 3.45 * channel
            row.append(temp)

        queue.put([delay1]+row)

        #print voltage variables to local file
        with open(filename, 'a') as DAQrecording:
            time1 = delay1.strftime('%Y-%m-%d')
            time2 = delay1.strftime('%H:%M:%S')
            row = [time1, time2] + row
            row = map(str, row)
            DAQrecording.write('{}\n'.format(', '.join(row)))

        #Delay until next 5 second interval
        delay2 = DT.datetime.now()
        difference = (delay2 - delay1).total_seconds()
        time.sleep(write_delay - difference)

def main():
    global fig, ax, lines
    queue = mp.Queue()
    proc = mp.Process(target=write_data, args=(filename, queue))
    # terminate proc when main process ends
    proc.daemon = True
    # spawn the writer in a separate process
    proc.start()

    fig, ax = plt.subplots()
    xfmt = mdates.DateFormatter('%H:%M:%S')
    ax.xaxis.set_major_formatter(xfmt)
    # make matplotlib treat x-axis as times
    ax.xaxis_date()

    fig.autofmt_xdate(rotation=25)

    lines = []
    for i in range(nlines):
        line, = ax.plot([], [])
        lines.append(line)

    ani = animation.FuncAnimation(fig, animate, interval=read_delay, fargs=(queue,))
    plt.show()    

if __name__ == '__main__':
    main()

答案 1 :(得分:0)

我今天开始工作,做我需要的一切!感谢你的帮助。最终产品可以:

  1. 在左侧的一个图表中显示8个模拟传感器的读数,每5秒刷新一次,仅显示最后5分钟的数据。
  2. 右侧图表用作白色画布,显示已读取和绘制的最后一个值。我无法弄清楚如何每隔5秒清除一次,所以文本框的白色背景覆盖了旧值。
  3. 所有数据都被写入并保存到一个文本文件中,日期和时间标有日(D / M / Y)和时间(H:M:S)。
  4. 对于其他可能对此类事情感兴趣的人,代码如下:

    import Queue
    import os
    import sys
    import datetime as DT
    import collections
    import matplotlib.pyplot as plt
    from matplotlib import gridspec
    import numpy as np
    import multiprocessing as mp
    import time
    import datetime
    import matplotlib.dates as mdates
    import matplotlib.animation as animation
    from ABE_DeltaSigmaPi import DeltaSigma 
    from ABE_helpers import ABEHelpers
    
    i2c_helper = ABEHelpers() 
    bus = i2c_helper.get_smbus() 
    adc = DeltaSigma(bus, 0x68, 0x69, 16)
    
    #Rename file to date
    base_dir = '/home/pi/Desktop/DATA'
    ts = time.time()
    filename_time = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d')
    filename_base = os.path.join(base_dir, filename_time)
    filename = '%s.txt' % filename_base
    
    # you will want to change read_delay to 5000
    read_delay = int(5000)    # in milliseconds 
    write_delay = read_delay/1000.0  # in seconds 
    window_size = 60
    nlines = 8
    ypadding = 0.5
    datenums = collections.deque(maxlen=window_size)
    ys = [collections.deque(maxlen=window_size) for i in range(nlines)]
    
    def animate(i, queue):
        try:
            row = queue.get_nowait()
        except Queue.Empty:
            return
        datenums.append(mdates.date2num(row[0]))
        for i, y in enumerate(row[1:]):
            ys[i].append(y)
        for i, y in enumerate(ys):
            lines[i].set_data(datenums, y)
        ymin1 = min(min(y) for y in ys)
        ymin = ymin1 - ypadding
        ymax1 = max(max(y) for y in ys)
        ymax = ymax1 + ypadding
        xmin = min(datenums)
        xmax = max(datenums)
        if xmin < xmax:
            ax1.set_xlim(xmin, xmax)
        ax1.set_ylim(ymin, ymax)
    
        ax2.plot(0, 0)
        ax2.set_xlim(0, 1)
        ax2.set_ylim(0, 1)
        channel1 = row[-8]
        channel2 = row[-7]
        channel3 = row[-6]
        channel4 = row[-5]
        channel5 = row[-4]
        channel6 = row[-3]
        channel7 = row[-2]
        channel8 = row[-1]
    
        ax2.text(0.1,0.8,'CH1: %.02f \n CH2: %.02f \n CH3: %.02f \n CH4: %.02f \n CH5: %.02f \n CH6: %.02f \n CH7: %.02f \n CH8: %.02f \n' % (channel1,channel2,channel3,channel4,channel5,channel6,channel7,channel8) , ha='left', va='top', backgroundcolor='w')
        fig.canvas.draw()
    
    def write_data(filename, queue):
        while True:
            delay1 = DT.datetime.now()
            row = []
            for i in range(nlines):
                # read from adc channels and print to screen
                channel = adc.read_voltage(i)
                row.append(channel)
    
            queue.put([delay1]+row)
    
            #print voltage variables to local file
            with open(filename, 'a') as DAQrecording:
                time1 = delay1.strftime('%Y-%m-%d')
                time2 = delay1.strftime('%H:%M:%S')
                row = [time1, time2] + row
                row = map(str, row)
                DAQrecording.write('{}\n'.format(', '.join(row)))
    
            #Delay until next 5 second interval
            delay2 = DT.datetime.now()
            difference = (delay2 - delay1).total_seconds()
            time.sleep(write_delay - difference)
    
    def main():
        global fig, ax1, ax2, lines
        queue = mp.Queue()
        proc = mp.Process(target=write_data, args=(filename, queue))
        # terminate proc when main process ends
        proc.daemon = True
        # spawn the writer in a separate process
        proc.start()
    
        fig, (ax1, ax2) = plt.subplots(1, 2, sharey=False) 
        gs = gridspec.GridSpec(1,2, width_ratios=[3, 1] wspace=None)
        ax1 = plt.subplot(gs[0])
        ax2 = plt.subplot(gs[1])
        ax2.axes.xaxis.set_ticklabels([])
        ax2.axes.yaxis.set_ticklabels([])
        xfmt = mdates.DateFormatter('%H:%M:%S')
        ax1.xaxis.set_major_formatter(xfmt)
    
        # make matplotlib treat x-axis as times
        ax1.xaxis_date()
        fig.autofmt_xdate()
        fig.suptitle('Data Acquisition', fontsize=14, fontweight='bold')
    
        lines = []
        for i in range(nlines):
            line, = ax1.plot([], [])
            lines.append(line)
    
        ani = animation.FuncAnimation(fig, animate, interval=read_delay, fargs=(queue,))
        plt.show()    
    
    if __name__ == '__main__':
        main()