带有图

时间:2016-10-04 17:36:31

标签: python matplotlib

我只是将我的脚趾浸入Python并在此处获得帮助以获得实时更新Matplotlib图形以便为我工作。该程序使用动画从动态增长的CSV文件中提取数据,其数据如下所示:

TimeStamp, ReadCount, Antenna, Protocol, RSSI, EPC, Sensor
09/28/2016 17:34:28.967, 5686, 2, GEN2, -25, E036115348A908CB, 23.16,0.00,0.00, (Infinity%), 
09/28/2016 17:34:29.716, 5687, 2, GEN2, -32, E036115348A908CB,  (Infinity%), 
09/28/2016 17:34:31.155, 5689, 2, GEN2, -27, E036115348A908CB, 22.74,3.38, (Infinity%), 
09/28/2016 17:34:32.351, 5692, 2, GEN2, -25, E036115348A908CB, 22.95,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:32.895, 5695, 2, GEN2, -23, E036115348A908CB, 22.95,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:33.397, 5698, 2, GEN2, -21, E036115348A908CB, 23.78,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:33.946, 5699, 2, GEN2, -23, E036115348A908CB, 23.57,0.00,3.38, (Infinity%), 
09/28/2016 17:34:34.912, 5702, 2, GEN2, -27, E036115348A908CB, 23.36,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:35.394, 5705, 2, GEN2, -25, E036115348A908CB, 23.36,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:35.988, 5707, 2, GEN2, -23, E036115348A908CB, 23.78,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:36.489, 5710, 2, GEN2, -21, E036115348A908CB, 23.99,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:37.269, 5712, 2, GEN2, -23, E036115348A908CB, 23.78,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:37.796, 5715, 2, GEN2, -18, E036115348A908CB, 23.78,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:38.296, 5718, 2, GEN2, -7, E036115348A908CB, 22.32,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:38.826, 5721, 2, GEN2, -7, E036115348A908CB, 23.57,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:39.320, 5724, 2, GEN2, -30, E036115348A908CB, 23.36,0.00,0.00,3.38, (Infinity%), 
09/28/2016 17:34:39.870, 5727, 2, GEN2, -9, E036115348A908CB, 23.36,0.00,0.00,3.38, (Infinity%), 

此数据来自传感器,我希望能够在显示器上随此图拉出/显示此数据包含的其他一些值。该图的代码如下所示:

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.animation as animation

from datetime import datetime, timedelta
import collections
import csv

offset = 16
slope = -.2081

def plot(ax, data, colour, width):
    if data:
        last_dt = data[0][0]
        gap = timedelta(seconds=10)

        x = []
        y = []

        # Plot groups of data not more than 60 seconds apart
        for dt, ten in data:
            if dt <= last_dt + gap:
                x.append(dt)
                y.append(ten)
            else:
                ax.plot(matplotlib.dates.date2num(x), y, colour, linewidth=width)
                x = [dt]
                y = [ten]

            last_dt = dt

        ax.plot(matplotlib.dates.date2num(x), y, colour, linewidth=width)


def animate(i, fig, ax):
    # Read in the CSV file
    data = collections.defaultdict(list)
    fields = ["TimeStamp", "ReadCount", "Antenna", "Protocol", "RSSI", "EPC", "Temp", "Ten", "Powr", "Unpowr", "Inf"]

    with open('SensorLogFile.csv') as f_input:
        csv_input = csv.DictReader(f_input, skipinitialspace=True, fieldnames=fields)
        header = next(csv_input)

        # Separate the rows based on the Antenna field
        for row in csv_input:
            try:
                data[row['Antenna']].append(
                    [datetime.strptime(row['TimeStamp'], '%m/%d/%Y %H:%M:%S.%f'), 
                    int(float(row['Ten']) * float(slope) + float(offset))])
            except:
                pass

    # Drop any data points more than 1.5 mins older than the last entry

    latest_dt = data[row['Antenna']][-1][0]     # Last entry
    not_before = latest_dt - timedelta(minutes=.25)

    for antenna, entries in data.items():
        data[antenna] = [[dt, count] for dt, count in entries if dt >= not_before]

    # Redraw existing axis
    ax.clear()

    ax.spines['bottom'].set_color("#5998ff")
    ax.spines['top'].set_color("#5998ff")
    ax.spines['left'].set_color("#5998ff")
    ax.spines['right'].set_color("#5998ff")

    hfmt = matplotlib.dates.DateFormatter('%m/%d/%Y\n%I:%M:%S %p')
    ax.xaxis.set_major_formatter(hfmt)
    fig.autofmt_xdate()

    plot(ax, data['1'], 'c', 6)     # Antenna 1
    plot(ax, data['2'], 'r', 6)     # Antenna 2
    plot(ax, data['3'], 'y', 6)     # Antenna 3

    ax.grid(True, color='w')
    plt.ylabel('Tension (lb)', color='w', fontsize=20)
    plt.title('Spiral 1 Tension', color='w', fontsize=26)

    ax.tick_params(axis='y', colors='w')
    ax.tick_params(axis='x', colors='w')

#    ax.set_ylim([21,28])

fig = plt.figure(facecolor='#07000d')
ax = fig.add_subplot(111, axisbg='#07000d')

ani = animation.FuncAnimation(fig, animate, fargs=(fig, ax), interval=250)
plt.show()

我希望能够将图形放在图形的下方和图形下方的开放区域(图形的整个宽度),我可以在其中放置以下内容(可能有一个框用于每个部分的数据):

  • &#34;温度&#34; (每行第7个csv,只需转换为deg F)
  • &#34;时间&#34; (当前时间)
  • &#34;高速模式&#34; (没有显示任何有关此数据的信息,但将来只是一个占位符)
  • &#34;循环&#34; (将是在一分钟间隙后首次阅读天线1的次数)
  • 包含右下方图片的框 - 例如,请说出此图片this image here

我已经研究过使用Tkinter并尝试关注sentdex&#39; s video here

但未能让它发挥作用。

我正处于紧张状态,不能再独自奋斗 - 需要专业人士的帮助。任何人都可以给我一些关于如何制作像我正在寻找的显示器的方向/指导吗?

1 个答案:

答案 0 :(得分:1)

为了帮助您入门,可能首先要回答一些问题。

  1. 如何生活?它应该实时更新吗?在这种情况下,使用FuncAnimation可能是一个坏主意。 答案:是的,实时
  2. 它的速度有多快,也就是说,每秒有多少次更新? 答案:每秒更新4次
  3. 是否有更新的触发器?你知道新数据什么时候到来吗? 答案:没有真正的触发器,但请参见2.
  4. 您需要多少互动?它只是应该打开然后运行的情节,还是需要交互式按钮/滑块才能选择部分数据?即使有一些基本的交互性,我建议使用交互式后端留在matplotlib中,而不是过多地使用tkinter - 因为你似乎对它一无所知并且时间有限。 答案:不需要互动
  5. 说到你的数据,我发现了一个问题。看着那些线 E036115348A908CB, 22.74,3.38, (Infinity%),
    E036115348A908CB, 22.95,0.00,0.00,3.38, (Infinity%),
    似乎有数据不完整的情况?!这是可以避免的吗?

  6. 情节的时间轴怎么样?首先,您#Drop any data points more than 1.5 mins older than the last entry然后是#Plot groups of data not more than 60 seconds apart,然后丢弃任何早于gap = timedelta(seconds=10)的数据。你能告诉我们什么&#34;数据组&#34;意味着时间轴应该是多长时间?

  7. 您如何计算number of cycles

  8. <小时/> 结果(目前为止): 我们走了,这是matplotlib可以轻松搞定的。

    enter image description here

    import matplotlib
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    
    from datetime import datetime, timedelta
    import collections
    import csv
    
    class Anim():
        """
        This class provides a "live" plot of the contents of a log file in csv format. 
        The class structure makes it easy to separate the plot generation from the
            frequent updating of the plot.
        The code is based on a question at stackoverflow
            http://stackoverflow.com/questions/39858501/python-data-display-with-graph
        """
        def __init__(self):
    
            self.offset = 16.
            self.slope = -.2081
    
            self.i = 0
    
            self.axisbg = '#07000d'
    
            self.fig = plt.figure(figsize=(15,8), facecolor=self.axisbg)
            self.ax = self.fig.add_subplot(111, axisbg=self.axisbg)
    
            [self.ax.spines[wh].set_color("#5998ff") for wh in ['bottom', 'top', 'left', 'right']]
    
            self.hfmt = matplotlib.dates.DateFormatter('%m/%d/%Y\n%I:%M:%S %p')
            self.ax.xaxis.set_major_formatter(self.hfmt)
            self.fig.autofmt_xdate()
    
            #self.framenumber = plt.figtext(0.9, .9, "0",  color='w')
            self.ax.grid(True, color='w')
            plt.ylabel('Tension (lb)', color='w', fontsize=20)
            plt.title('Spiral 1 Tension', color='w', fontsize=26)
    
            self.ax.tick_params(axis='y', colors='w')
            self.ax.tick_params(axis='x', colors='w')
    
            initialx = [self.stime("09/28/2016 17:34:28.967"),self.stime("09/28/2016 17:34:29.716") ]
            initialy = [0,0 ]
    
            self.line1, = self.ax.plot(matplotlib.dates.date2num(initialx), initialy, color="c", linewidth=6)
            self.line2, = self.ax.plot(matplotlib.dates.date2num(initialx), initialy, color="r", linewidth=6)
            self.line3, = self.ax.plot(matplotlib.dates.date2num(initialx), initialy, color="y", linewidth=6)
    
            plt.subplots_adjust(left=0.1, bottom=0.28, right=0.9, top=0.9, wspace=0, hspace=0)
    
            self.ax_temp =      plt.axes([0.1, 0.08, 0.2, 0.06], axisbg=self.axisbg)
            self.ax_time =      plt.axes([0.2, 0.08, 0.2, 0.06], axisbg=self.axisbg)
            self.ax_overdrive = plt.axes([0.4, 0.08, 0.2, 0.06], axisbg=self.axisbg)
            self.ax_cycles =    plt.axes([0.5, 0.08, 0.2, 0.06], axisbg=self.axisbg)
            self.ax_image =    plt.axes([0.75, 0.03, 0.3, 0.2], axisbg=self.axisbg)
    
            self.tx_temp = self.ax_temp.text(0,0, "Temp", color="w", transform=self.ax_temp.transAxes, bbox={"pad" : 10, "ec" : "w", "fc" : self.axisbg})
            self.tx_time = self.ax_time.text(0,0, "Time", color="w", transform=self.ax_time.transAxes, bbox={"pad" : 10, "ec" : "w", "fc" : self.axisbg})
            self.tx_overdrive = self.ax_overdrive.text(0,0, "Overdrive", color="w", transform=self.ax_overdrive.transAxes, bbox={"pad" : 10, "ec" : "w", "fc" : self.axisbg})
            self.tx_cycles = self.ax_cycles.text(0,0, "Cyles", color="w", transform=self.ax_cycles.transAxes, bbox={"pad" : 10, "ec" : "w", "fc" : self.axisbg})
    
            self.ax_image.imshow(mpimg.imread('mmbRy.jpg'))
            self.ax_image.tick_params(axis='x',which='both',bottom='off', top='off',labelbottom='off')
            self.ax_image.tick_params(axis='y',which='both',left='off', right='off',labelleft='off')
            [self.ax_image.spines[wh].set_color("#5998ff") for wh in ['bottom', 'top', 'left', 'right']]
    
            self.timer = self.fig.canvas.new_timer(interval=250, callbacks=[(self.animate, [], {})])
            self.timer.start()
            plt.show()
    
    
        def plot(self, data, line):
            if data:
                last_dt = data[0][0]
                gap = timedelta(seconds=10)
                x = []
                y = []
                # Plot groups of data not more than 60 seconds apart
                for dt, ten in data:
                    if dt <= last_dt + gap:
                        x.append(dt)
                        y.append(ten)
                    else:
                        line.set_data(matplotlib.dates.date2num(x), y)
                        #ax.plot(, colour, linewidth=width)
                        x = [dt]
                        y = [ten]
                    last_dt = dt
                line.set_data(matplotlib.dates.date2num(x), y)
    
    
        def animate(self):
            self.i +=1 #counting the number of frames
            # Read in the CSV file
            data = collections.defaultdict(list)
            fields = ["TimeStamp", "ReadCount", "Antenna", "Protocol", "RSSI", "EPC", "Temp", "Ten", "Powr", "Unpowr", "Inf"]
            temp = ""
            # the complete file is read in, which might be a problem once the file gets very large
            with open('SensorLogFile.csv') as f_input:
                csv_input = csv.DictReader(f_input, skipinitialspace=True, fieldnames=fields)
                header = next(csv_input)
                # Separate the rows based on the Antenna field
                for row in csv_input:
                    try:
                        data[row['Antenna']].append([self.stime(row['TimeStamp']), self.rten(row['Ten']) ])
                        temp= row['Temp']
                    except:
                        pass
    
            # Drop any data points more than 1.5 mins older than the last entry
            latest_dt = data[row['Antenna']][-1][0]     # Last entry
            not_before = latest_dt - timedelta(minutes=.25)
    
            for antenna, entries in data.items():
                data[antenna] = [[dt, count] for dt, count in entries if dt >= not_before]
    
            self.plot(data['1'],  self.line1)     # Antenna 1
            self.plot(data['2'],  self.line2)     # Antenna 2
            self.plot(data['3'],  self.line3)     # Antenna 3
    
            #Filling the text boxes
            self.tx_temp.set_text(u"Temperature\n{temp:.2f} °F".format(temp=self.deg2F(temp)))
            self.tx_time.set_text("Time\n{time}".format(time=datetime.now().time()) )
            self.tx_overdrive.set_text("Overdrive\nfill later")
            #Todo: how do you calculate this?
            self.tx_cycles.set_text("Cyles\n{cyles}".format(cyles=self.i)) 
            #Todo: setting the limits correctly, depending on the user's need
            self.ax.set_ylim([0,16])     
            self.ax.set_xlim([matplotlib.dates.date2num(not_before), matplotlib.dates.date2num(latest_dt)])
            #Update the canvas
            self.fig.canvas.draw()
    
    
        def deg2F(self,deg):
            return float(deg) * 9./5. + 32. 
    
        def stime(self, timestamp):
            return datetime.strptime(timestamp, '%m/%d/%Y %H:%M:%S.%f')
    
        def rten(self, ten):
            return int(float(ten) * self.slope + self.offset)
    
    
    if __name__ == "__main__":
        Anim()