1. 程式人生 > >[Python-Matplotlib] 動態圖表繪製來達到實時監控

[Python-Matplotlib] 動態圖表繪製來達到實時監控

再加上了滾動條與暫停功能。程式碼中還包含了一些小的功能,例如可以對每個數值進行設定y-value。但是我綜合考慮了最終的效果,最後都註釋掉了,如果有需要的話,可以取消註釋來使用。

最終效果如下:

影象會根據資料實時進行更新,也就是資料跟影象都是實時重新整理的。表格會顯示最近的五個數值。如果直接拉動滾動條的話,可能反應會有點慢。可以先按下 “Pause” 按鈕,暫停繪圖,然後拉動下方的滾動條來回顧過去的資料。

程式碼分為兩個部分,一部分是資料如何產生,第二部分為圖表繪製。

1. 資料產生

資料是實時產生的(初始是沒有的,需要成功登入網頁後獲取到相關資料後才有),利用Selenium,每5秒重新整理一某網頁,並呼叫JS "Windonw.performance.timing“ 來計算完全載入所需時間,並得到當前時間。有關Selenium的使用,可以谷歌相關的用法。可能有空的時候我也寫個小教程,當初踩了不少坑.....

2. 圖表繪製

利用ion來繪製動態圖。那麼分為三大部分

  1. 1) 初始值的設定 
  2. 2)框架的定義
  3. 3)資料傳入並繪製
  4. 4 ) 關閉ion並顯示影象

重點講解下一下幾點

  • 資料如何傳入

簡單來說就是要讓資料的兩個因素, dtime還有onloadingtime能夠傳入,需要結合下面的呼叫環節來理解。這裡就是簡單地在函式DetectionPlot那裡傳入引數,並把新得到的引數,附加成為列表型別。

  • 橫縱座標的設定
self.loadingGraph.xaxis.set_ticks(self.timestamp1)
self.loadingGraph.yaxis.set_ticks(self.loadingValue1)

如果直接設定了set_ticks的話,那麼以下這幾行程式碼將不會生效,那麼圖示的橫縱座標就會不斷地壓縮。

self.loadingGraph.set_ylim(
                min(self.loadingValueRange), max(self.loadingValueRange))
self.loadingGraph.set_xlim(
                self.timestampRange[1] - dt.timedelta(minutes=1), self.timestampRange[1])

另外注意一點就是,如果你想橫座標是時間,你需要首先將時間從string型別轉換為datetime型別,這樣才能夠與datetime.timedelta進行相加減。然後利用下面的兩行程式碼,將橫座標的格式定義為datetime型別,那麼Matplotlib就能幫你處理。縱座標也是相同的道理。

self.dateFormat = DateFormatter("%m-%d %H:%M:%S")
self.loadingGraph.xaxis.set_major_formatter(ticker.FuncFormatter(self.dateFormat))
  • 滾動條與暫停功能

這兩個部分,就是首先定義相關的位置,然後與功能函式掛鉤。Matplotlib的API上有相關的簡介。

這裡具體說一下,由於橫座標是時間型別,那麼怎麼設定滾動條。

首先Slider定義上包含了一個最小值,跟最大值。這裡要對datetime型別進行轉換。

功能定義函式上,就要轉換為datetime型別,要不然matplotlib識別不了。然後就是利用拉動的變數來定義橫座標。

# Add a scroll bar
        self.axcolor = 'lightgoldenrodyellow'
        self.axsb = fig.add_axes([0.06, 0.25, 0.65, 0.02], facecolor=self.axcolor)

#Slider setting
        self.ssb = Slider(self.axsb, 'Scrollbar',
                              dates.date2num(self.timestampRange[0]),
                              dates.date2num(self.timestampRange[1]))
        self.ssb.on_changed(self.update)

#Define the slider update function
    def update(self,val):
        self.sb=self.ssb.val
        self.xmin_time=dates.num2date(self.sb)-dt.timedelta(minutes=1)
        self.xmax_time=dates.num2date(self.sb)
        self.loadingGraph.axis([self.xmin_time,self.xmax_time,min(self.loadingValueRange), max(self.loadingValueRange)])
        fig.canvas.draw_idle()

3. 呼叫

資料部分由於需要實時返回,因此我使用了yield這個generator。注意不要用return,return只能返回一次值就會停止了。

當需要使用yield回來的兩個值時候:

    for times,values in Getdata():
        graph.DetectionPlot(times,values)

你也可以使用靜態形式來檢視圖表的情況,取消註釋 以下兩段。

timelist = ['08-31 11:17:27', '08-31 11:17:34', '08-31 11:17:41', '08-31 11:18:27',
             '08-31 11:18:47', '08-31 11:19:47','08-31 11:19:49']
onloadlist = ['25032', '6558', '383', '3383', '1111', '2345','5000']
#If timelist and onloadlist is not "#", you can use the following to do the static test.
for i in range(len(timelist)):
    graph.DetectionPlot(timelist[i], onloadlist[i])

然後註釋掉上面的Getdata()部分。

完整程式碼如下:

from matplotlib.widgets import Button, Slider
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter, DayLocator
import matplotlib.ticker as ticker
from datetime import datetime
import matplotlib.transforms as transforms
from matplotlib import dates
import getpass
import time
import sys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.options import Options
from datetime import datetime
from selenium.common.exceptions import NoSuchElementException
from selenium import webdriver
import matplotlib
matplotlib.use('TkAgg')

class streamDetectionPlot(object):
    # Initial the figure parameters
    def __init__(self):
        # Turn the interactive mode on
        plt.ion()
        # initial the plot variable
        self.timestamp = []
        self.loadingValue = []
        self.highlightList = []
        self.highlightListTurnOn = True
        self.loadingValueRange = [0, 1]
        self.timestampRange = [0, 1]
        self.tableValue = [[0, 0]]
        self.timestamp1 = []
        self.loadingValue1 = []

        # initial the figure
        global fig
        fig = plt.figure(figsize=(18, 8), facecolor="white")
        fig.subplots_adjust(left=0.06, right=0.70)
        self.loadingGraph = fig.add_subplot(2, 1, 1)
        ##add_axes(rect,**kwargs) Meaning:##rect: left,bottom,width,height
        self.loadingTable = fig.add_axes([0.72, 0.1, 0.2, 0.8], frameon=False)

        # Add a scroll bar
        self.axcolor = 'lightgoldenrodyellow'
        self.axsb = fig.add_axes([0.06, 0.25, 0.65, 0.02], facecolor=self.axcolor)

        # Add the pause button
        self.pauseax = fig.add_axes([0.8, 0.25, 0.05, 0.02], facecolor=self.axcolor)

    # define the initial plot method
    def initPlot(self):
        # initial two lines
        self.line, = self.loadingGraph.plot_date(self.timestamp, self.loadingValue, fmt="-", color="red",
                                                 label="LoadingValue")
        self.loadingGraph.legend(loc="upper right", frameon=False)
        self.loadingGraph.grid(True)

        # Set the baseline of 5000, horizen use "axhline" while vertical uses "axvline"
        self.baseline = self.loadingGraph.axhline(5000, color='black', lw=1)

        # Add the "5000" to the y-axis label next to the line
        # trans = transforms.blended_transform_factory(
        #     self.loadingGraph.get_yticklabels()[0].get_transform(), self.loadingGraph.transData)
        # self.loadingGraph.text(0, 5000, "{:.0f}".format(5000), color="black", transform=trans, ha="right", va="center")

        # Set the title
        self.loadingGraph.set_title("Live update test")

        # set the x/y label of the first graph
        self.loadingGraph.set_xlabel("datetime")
        self.loadingGraph.set_ylabel("Loading Time")

        # axis format
        self.dateFormat = DateFormatter("%m-%d %H:%M:%S")
        self.loadingGraph.xaxis.set_major_formatter(ticker.FuncFormatter(self.dateFormat))

        ##Configure the table
        self.loadingTableColumnName = ["timestamp", "Loading value"]
        self.loadingTable.set_xticks([])
        self.loadingTable.set_yticks([])

    # define the output method
    def DetectionPlot(self, timestamp, loadingValue):
        if not pause:
            # update the plot value of the graph
            self.timestamp.append(timestamp)
            self.loadingValue.append(loadingValue)

            # From string to datetime
            self.timestamp1 = [datetime.strptime(d, "%m-%d %H:%M:%S") for d in self.timestamp]
            self.loadingValue = [float(i) for i in self.loadingValue]

            # pretty date names
            plt.gcf().autofmt_xdate()

            # update the x/y range
            self.timestampRange = [min(self.timestamp1), max(self.timestamp1) + dt.timedelta(minutes=0.1)]  # datetime style
            self.loadingValueRange = [min(self.loadingValue), max(self.loadingValue) + 1]

            # update the x/y axis limits
            self.loadingGraph.set_ylim(
                min(self.loadingValueRange), max(self.loadingValueRange))
            self.loadingGraph.set_xlim(
                self.timestampRange[1] - dt.timedelta(minutes=1), self.timestampRange[1])

            # Set the y-ticks if the variation is above 1000
            # https://stackoverflow.com/questions/39969217/ytick-overlapping-in-matplotlib
            # self.loadingValue1 = [min(self.loadingValue)]
            # for i in sorted(self.loadingValue[0:]):
            #     if i - self.loadingValue1[-1] > 1000:
            #         self.loadingValue1.append(i)

            # Set the ticks
            # self.loadingGraph.xaxis.set_ticks(self.timestamp1)
            # self.loadingGraph.yaxis.set_ticks(self.loadingValue1)

            # update the two lines
            self.line.set_xdata(self.timestamp1)
            self.line.set_ydata(self.loadingValue)

            # The x-data is being updated, but the plot ranges are not. When I put new data on the plot, it was all out of range. The solution was to add:
            self.loadingGraph.relim()
            self.loadingGraph.autoscale_view()

            # Rotate the x-array
            for tick in self.loadingGraph.get_xticklabels():
                tick.set_rotation(15)

            # Plot the value of y on the plot.
            # for xp, yp in zip(self.timestamp1[1:-1], self.loadingValue[1:-1]):
            #     label = "%s" % yp
            #     self.loadingGraph.text(xp, yp, label, fontsize=8, horizontalalignment='right', verticalalignment='bottom')

            #Clear the text first
            for txt in self.loadingGraph.texts:
                txt.set_visible(False)
            #Set the maximum and minimum value of y on the plot.
            self.max_y, self.min_y = max(self.loadingValue), min(self.loadingValue)
            self.max_x, self.min_x = self.timestamp1[self.loadingValue.index(self.max_y)], self.timestamp1[
                self.loadingValue.index(self.min_y)]
            self.maxlabel, self.minlabel = "Max: %s ms" % self.max_y, "Min: %s ms" % self.min_y
            self.loadingGraph.text(self.max_x, self.max_y, self.maxlabel, fontsize=8, horizontalalignment='right',
                                   verticalalignment='bottom')
            self.loadingGraph.text(self.min_x, self.min_y, self.minlabel, fontsize=8, horizontalalignment='right',
                                   verticalalignment='bottom')


            # update the highlight of the graph. The x will be 1 second varitation
            if int(loadingValue) >= 5000:
                self.highlightList = self.timestamp1
                self.highlightListTurnOn = True
            else:
                self.highlightListTurnOn = False
            if len(self.highlightList) != 0 and self.highlightListTurnOn is False:
                self.loadingGraph.axvspan(
                    self.highlightList[0] - dt.timedelta(seconds=1),
                    self.highlightList[-1] + dt.timedelta(seconds=1),
                    color='r',
                    edgecolor=None,
                    alpha=0.2
                )
                self.highlightList = []
                self.highlightListTurnOn = True

            # Update the table with the latest 5 entries
            self.loadingTableColumnName = ["timestamp", "Loading value"]
            self.loadingTable.text(0.15, 1, "LoadingTable", size=12)
            self.loadingTable = fig.add_axes([0.72, 0.1, 0.2, 0.8], frameon=False)
            self.loadingTable.set_xticks([])
            self.loadingTable.set_yticks([])
            self.tableValue.append([timestamp, loadingValue])

            if len(self.tableValue) >= 6: self.tableValue.pop(0)
            self.loadingTable.table(cellText=self.tableValue,
                                    colWidths=[0.5] * 2,
                                    colLabels=self.loadingTableColumnName,
                                    loc=1,
                                    cellLoc='center'
                                    )

            #Slider setting
            self.ssb = Slider(self.axsb, 'Scrollbar',
                              dates.date2num(self.timestampRange[0]),
                              dates.date2num(self.timestampRange[1]))
            self.ssb.on_changed(self.update)

        #Pause Button setting
        self.button=Button(self.pauseax,'Pause',color='0.85',hovercolor='0.975')
        self.button.on_clicked(self.setpause)


        # plot pause 0.0001 second and then plot the next one.
        plt.pause(1)
        plt.draw()

    #Define the slider update function
    def update(self,val):
        self.sb=self.ssb.val
        self.xmin_time=dates.num2date(self.sb)-dt.timedelta(minutes=1)
        self.xmax_time=dates.num2date(self.sb)
        self.loadingGraph.axis([self.xmin_time,self.xmax_time,min(self.loadingValueRange), max(self.loadingValueRange)])
        fig.canvas.draw_idle()

    #Define the pause button function
    def setpause(self,event):
        global pause
        pause = not pause
        print(pause)

    #Turn off the ion and show the plot.
    def close(self):
        plt.ioff()
        plt.show()



######################Data Part############################

def verificationcode():
    ##Test if the verification page exists or not
    key = input("Please input your verfication code:")
    if driver.find_element_by_id("smc"):
        verification = driver.find_element_by_id("smc")
        verification.send_keys(key)
        # if driver.find_element_by_id("emc"):
        #     emailverification = driver.find_element_by_id("emc")
        #     emailverification.send_keys(key)
    driver.find_element_by_id("save").click()

def Getdata():

    driver.get(source)

    try:
        driver.find_element_by_id("Login").click()
    except NoSuchElementException:
        print("Don't find the login button")

    while not driver.find_elements_by_id("cas2_ilecell"):
        if driver.find_elements_by_id("smc"):
            for i in range(1, 4):
                try:
                    verificationcode()
                    if driver.find_elements_by_id("smc-error"):
                        verificationcode()
                    else:
                        break
                except IOError:
                    break
        elif driver.find_elements_by_id("editPage"):
            print("Too much tries, please try it later")
            driver.quit()
    else:
        # print("Welcome")
        while True:
            try:

                navigationStart = driver.execute_script("return window.performance.timing.navigationStart")
                # domComplete = driver.execute_script("return window.performance.timing.domComplete")
                loadEvent = driver.execute_script("return window.performance.timing. loadEventEnd")
                onloadPerformance = loadEvent - navigationStart
                dtime = datetime.now().strftime("%m-%d %H:%M:%S")
                # print(dtime, ",", onloadPerformance, "ms")
                yield dtime,onloadPerformance

                time.sleep(2)
                driver.refresh()

            except TimeoutException:
                print("It took too long")
                break
        driver.quit()


# timelist = ['08-31 11:17:27', '08-31 11:17:34', '08-31 11:17:41', '08-31 11:18:27',
#             '08-31 11:18:47', '08-31 11:19:47','08-31 11:19:49']
# onloadlist = ['25032', '6558', '383', '3383', '1111', '2345','5000']

if __name__ == '__main__':
    # Get the local user name
    u = getpass.getuser()

    # # initialize Chrome options
    chrome_options = Options()
    # chrome_options.add_argument('--headless')

    chrome_options.add_argument('user-data-dir=C:\\Users\\%s\\AppData\\Local\\Google\\Chrome\\User Data' % (u))

    # chrome_driver_binary="E:\MyDownloads\Download\chromedriver.exe"
    source = "https://na66.salesforce.com/5000y00001SgXm0?srPos=0&srKp=500"
    driver = webdriver.Chrome(chrome_options=chrome_options)

    # Use the graph class
    graph = streamDetectionPlot()
    graph.initPlot()
    pause = False

    # Dynamic Test
    for times,values in Getdata():
        graph.DetectionPlot(times,values)

    # If timelist and onloadlist is not "#", you can use the following to do the static test.
    # for i in range(len(timelist)):
    #     graph.DetectionPlot(timelist[i], onloadlist[i])

    graph.close()

謝謝看到最後,希望對你有幫助。

相關推薦

[Python-Matplotlib] 動態圖表繪製達到實時監控

再加上了滾動條與暫停功能。程式碼中還包含了一些小的功能,例如可以對每個數值進行設定y-value。但是我綜合考慮了最終的效果,最後都註釋掉了,如果有需要的話,可以取消註釋來使用。 最終效果如下: 影象會根據資料實時進行更新,也就是資料跟影象都是實時重新整理的。表格會顯

利用redis的訂閱和釋出實現實時監控的一個DEMO(Python版本)

       redis的list型別有個很好的特性,就是每次新增元素後會返回當前list的長度,利用這個特點,我們可以監控它的長度,比如我們的key是使用者註冊的IP地址,list中存放的是已經在此IP地址上註冊的使用者的ID,當用戶數超過1000的時候來發一個告警,而r

python Matplotlib 系列教程(九)——如何繪製動態圖(類似實時股票圖=走勢圖)

本章我們討論的是如何繪製實時圖表,用到的知識是Matplotlib的動畫功能。 # -*- coding: utf-8 -*- import matplotlib.pyplot as plt im

Python-matplotlib-入門教程(一)-基礎圖表繪製

0.摘要 本教程主要介紹使用python第三方庫matplotlib繪製各種統計圖表,教程從簡單到複雜,逐步遞進。 本章主要介紹常見圖表的繪製方法,並以儘可能簡單的方式實現,主要以突出函式功能為目的,防止讀者被複雜的引數分散了注意力。鑑於函式的引數的相似性,讀者只需要知道引數的含義並結合he

使用python matplotlib繪製高階圖表

1.等值線圖 其中contour和contourf函式,前者表示繪製等高線,後者表示加色,個人覺得配合使用更好。 dx=0.01;dy=0.01 x=np.arange(-2.0,2.0,dx) y

Python圖表繪製matplotlib繪相簿入門

matplotlib 是python最著名的繪相簿,它提供了一整套和matlab相似的命令API,十分適合互動式地行製圖。而且也可以方便地將它作為繪圖控制元件,嵌入GUI應用程式中。 它的文件相當完備,並且Gallery頁面中有上百幅縮圖,開啟之後都有源程式。因此如果你需要繪製某種型別的圖,只需要在這個頁面

[Python] Matplotlib 圖表繪製和美化技巧

[TOC] ## 在一張畫布中繪製多個圖表 Matplotlib模組在繪製圖表時,預設先建立一張畫布,然後在畫布中顯示繪製的圖表。 如果想要在一張畫布中繪製多個圖表,可以使用subplot()函式將畫布劃分為幾個區域,然後在各個區域中分別繪製不同的圖表。 subplot()函式的引數為3個整型數字: +

python matplotlib 圖表局部放大

ren style conn pyplot show connect mar col ins import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1.inset_locator import zoomed

使用Python matplotlib動態曲線

point clas sin 參考 fig 如何使用 tput 運行圖 href 今天看到“Python實時監控CPU使用率”的教程: https://www.w3cschool.cn/python3/python3-ja3d2z2g.html 自己也學習如何使用Pytho

Python之PyQt5視覺化程式設計02——matplotlib動態顯示畫面

      matplotlib動態顯示畫面分為直接在figure圖形物件動態顯示畫面和在UI介面動態顯示畫面,但是兩者本質都是使用到了matplotlib中的animation模組,並呼叫其中的FuncAnimation(figure, update, interval..

Python matplotlib繪製餅圖

Python matplotlib繪製餅圖 最近用到了matplotlib庫繪製餅圖,之前也沒有做過,所以網上查閱了一些資料 plt.rcParams['font.sans-serif']=['SimHei'] # 用黑體顯示中文 plt.figure(figsize=(14,6))

python matplotlib模組——繪製三維圖形、三維資料散點圖

python matplotlib模組,是擴充套件的MATLAB的一個繪圖工具庫。他可以繪製各種圖形,可是最近最的一個小程式,得到一些三維的資料點圖,就學習了下python中的matplotlib模組,

python matplotlib 繪製雙Y軸曲線圖

要點就是ax2 = ax1.twinx(), 製作一個兄弟軸。程式碼如下: import matplotlib.pyplot as plt import numpy as np x = np.ara

python Matplotlib 系列教程(七)——從檔案載入資料並繪製

本章節我們將要學習如何讀取一個檔案的內容,並根據檔案的內容進行繪製。比如從csv檔案讀取資料,從txt檔案讀取資料等。 # -*- coding: utf-8 -*- import matplot

python matplotlib繪製gif動圖以及儲存

python matplotlib繪製gif動圖以及儲存 標籤: python matplotlib 謹以此文紀念我兩天來的悲劇 昨天我用lstm擬合sin曲線,看到別人畫的做的動圖很好看,並且還能儲存下來,所以我也想做著玩一下,但是沒想到在網上各種教程都不太對,最後還

python matplotlib從檔案中讀取資料繪製散點圖

示例說明:從一個檔案讀取資料,繪製成散點圖 #coding:utf-8 import matplotlib.pyplot as plt import numpy as np import matpl

Python Matplotlib 散點圖的繪製

之前使用matplotlib繪製曲線圖直接使用的是plot()方法,其實繪製基礎的散點圖很簡單,只要使用scatter()方法就可以了,其他的設定方式與曲線圖的設定方式也是一致的。 例如: import matplotlib.pyplot as plt impo

動態從資料庫獲取資料實時插入圖表

1.實現效果圖 2.jsp檔案 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="f

d3.js—— 繪製二維陣列的動態圖表

在繪製二維陣列的動態圖表之前,我們先來理一下思路: 1、我們需要繪製一張圖表; 2、這張圖表的資料來源是二維陣列; 3、這張圖表有動態效果。 那麼,我們一步一步來: 首先,我們來隨意寫一串二維陣列,確定資料來源: var data =[[1993,10],[1998,20]

python matplotlib從檔案中讀取資料繪製折線圖

說明:從檔案中讀取資料,繪製直線圖 #coding:utf-8 import matplotlib.pyplot as plt import matplotlib as mpl import num