之前一直用爬虫捉取路由实时上下载的记录用数据库保存,有时可用matplotlib来查看时间与上下传的曲线图,但是静态的,查询的时间段需自行认定,虽然qt的日历类可以比较方便取日期按日期查,但总觉要点有点麻烦,又不想看24小时的数据,截取最近几小时观看数据并实时展示应该是很好的方式,经百度发现pyqt有个很方便的库来展示动态数据,这个库是pyqtchart,安装PyQt时并没有这个库的,需另行安装,pip install pyqtchart安装就可以了,下面就结合代码和实际情况记录一下。

import sqlite3,sys,time
from datetime import datetime
from PyQt5.QtChart import QDateTimeAxis,QValueAxis,QSplineSeries,QChart,QChartView
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QPainter
from PyQt5.QtCore import QDateTime,Qt,QTimer

class ChartView(QChartView,QChart): #原代码如此,继承了两个类,其实去掉QChart也没影响
    def __init__(self, *args, **kwargs):
        super(ChartView, self).__init__(*args, **kwargs)
        self.connect = sqlite3.connect("netdata.db") #数据库,表名为t1,包括时间(年月日时分秒的方式,用sqlite的自动时间截生成的,为方便自己看,转成年月日,结果是个坑),下载速度,上传速度
        self.resize(1500, 500)
        self.setRenderHint(QPainter.Antialiasing)  # 抗锯齿,注释此行曲线很难看
        self.limitminute=240 #设置显示多少分钟内的活动
        self.maxspeed = 300 #预设y轴最大值
        self.chart_init()
        self.timer_init()

    def timer_init(self):
        #使用QTimer,2秒触发一次,更新数据
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.drawLine)
        self.timer.start(2000)

    def chart_init(self):
        self.chart = QChart()
        self.series = QSplineSeries() #这个是平滑曲线类,而QSplineSeries()是折线类,根所自己需求选用,下载数据曲线
        self.series_upload = QSplineSeries() #上传数据曲线
        #设置曲线名称
        self.series.setName("下载速度")
        self.series_upload.setName('上传速度')
        #把曲线添加到QChart的实例中
        self.chart.addSeries(self.series)
        self.chart.addSeries(self.series_upload)
        #声明并初始化X轴,Y轴
        self.dtaxisX = QDateTimeAxis()
        self.vlaxisY = QValueAxis()
        #设置坐标轴显示范围
        self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-self.limitminute*60))
        self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))
        self.vlaxisY.setMin(0)    
        self.vlaxisY.setMax(self.maxspeed) #设置y轴最大值

        #设置X轴时间样式
        self.dtaxisX.setFormat("hh:mm") #关注就是几小时内的数据,就留时分好了

        #设置坐标轴上的格点
        self.dtaxisX.setTickCount(15) #平均分的刻度分隔
        self.vlaxisY.setTickCount(10)
        #设置坐标轴名称
        self.dtaxisX.setTitleText("时间")
        self.vlaxisY.setTitleText("速度(M)")
        #设置网格显示,并设为灰色 
        self.vlaxisY.setGridLineVisible(True)
        self.vlaxisY.setGridLineColor(Qt.gray)
        self.dtaxisX.setGridLineVisible(True)
        self.dtaxisX.setGridLineColor(Qt.gray)
        #把坐标轴添加到chart中
        self.chart.addAxis(self.dtaxisX,Qt.AlignBottom)
        self.chart.addAxis(self.vlaxisY,Qt.AlignLeft)
        #把曲线关联到坐标轴
        self.series.attachAxis(self.dtaxisX)
        self.series.attachAxis(self.vlaxisY)

        self.series_upload.attachAxis(self.dtaxisX)
        self.series_upload.attachAxis(self.vlaxisY)

        self.setChart(self.chart)
    def drawLine(self):
        #获取当前时间
        bjtime = QDateTime.currentDateTime()
        #更新X轴坐标
        self.dtaxisX.setMin(bjtime.addSecs(-self.limitminute*60))
        self.dtaxisX.setMax(bjtime.addSecs(0))

        #设Y轴最大值,查询数据库最近4小时内的下载最大值,并乘1.2作为y轴最大值
        for xx in self.connect.execute(
                "select max(downdata) from t1 where time > datetime('now','-4 hour','localtime') order by time"):
            if xx:
                self.vlaxisY.setMax(int(xx[0] * 1.2))
            else:
                self.vlaxisY.setMax(self.maxspeed)

                
        if self.series.at(0): #self.serie存在索引0时,也就是起码有一个数据对过旧数据进行清除,self.series.removePoints两参数一个是索引,一个是从索引起始删除多少个数值,两条数据均如此处理
            if self.series.at(0).x()<bjtime.addSecs(-self.limitminute*60).toMSecsSinceEpoch(): #self.series.at(0).x()其实就是图像x坐标值,与原始数据可能并不完全相等,小数点后的值是约去了的,bjtime的toMSecsSinceEpoch()其实与time.time()相约,不过前者是整数,是后者的1000倍,所以后面需要转换
                self.series.removePoints(0, 1)

        if self.series_upload.at(0):
            if self.series_upload.at(0).x()<bjtime.addSecs(-self.limitminute*60).toMSecsSinceEpoch():
                self.series_upload.removePoints(0, 1)

        for xx in self.connect.execute("select * from t1 order by time desc limit 1"):
            #x1 = self.connect.execute("select strftime('%s',?)", (xx[0],)).fetchone()[0] #用此法转出来的时间截与time.time()整好差8个时区,用sqlite不知如何处理了
            x1=time.mktime(datetime.strptime(xx[0], '%Y-%m-%d %H:%M:%S').timetuple()) #用py内置库的办法有日期转为时间截
            x_time=int(x1)*1000 #再乘1000,以符号格式要求
            y0_value=xx[1] #取得下载数据
            y1_value=xx[2] #取得上传数据

            #添加数据到曲线末端
            if self.series.at(0):  #因数据库并非每秒更新,为免相同数据重复录入,先判断self.series起码有一个数据
                if x_time!=self.series.at(self.series.count()-1).x(): #假如最新的时间轴与数据库取得的不一致就录入,相同就跳过
                    self.series.append(x_time, y0_value)
            else: #当self.series为空时起码录入第一个数据,下面另外一轴同样处理
                self.series.append(x_time,y0_value)

            if self.series_upload.at(0):
                if x_time!=self.series_upload.at(self.series_upload.count()-1).x():
                    self.series_upload.append(x_time, y1_value)
            else:
                self.series_upload.append(x_time,y1_value)
            #print(self.series.count(),self.series_upload.count())

if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = ChartView()
    view.show()
    sys.exit(app.exec_())