在某些情况下,可能需要在窗口界面中显示动态图表来体现数据的更新变化。本人正好在做项目中碰到了这种情况,需要动态显示一个甘特图,就以此为例告诉大家怎么实现。首先,直接上完整代码:
import sys
import matplotlib
import datetime
matplotlib.use("Qt5Agg")
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QSizePolicy, QWidget
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
class MyMplCanvas(FigureCanvas):
def __init__(self, parent=None, width=5, height=4, dpi=100):
# 配置中文显示
plt.rcParams['font.family'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
self.fig = Figure(figsize=(width, height), dpi=dpi) # 新建一个figure
self.axes = self.fig.add_subplot(111) # 建立一个子图,如果要建立复合图,可以在这里修改
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
FigureCanvas.setSizePolicy(self,
QSizePolicy.Expanding,
QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
'''启动显示动态图'''
def Display_dynamic_gantt(self, *args, **kwargs):
# 设置一个时间对象
timer = QtCore.QTimer(self)
# 连接需要动态刷新的方法函数
timer.timeout.connect(self.update_figure)
# 表示每1秒钟刷新一次
timer.start(1000)
'''绘制动态图方法函数,可以在这里定义自己的绘图逻辑'''
def update_figure(self):
# 每次重新绘制前需要清楚之前绘制的内容
# 获取当前的系统时间
now = datetime.datetime.now()
self.axes.clear()
l1 = now.second * 1.8
if l1 > 60:
l1 = 60
l2 = now.second * 1.5
if l2 > 60:
l2 = 60
# 画甘特图
self.axes.barh((1, 2, 3, 4, 5), (0 + now.second, 0 + l1, 0 + now.second, 0 + l2, 0 + now.second), 0.5,
(0, 60, 120, 180, 240))
self.axes.set_yticks(range(1, 6, 1))
self.axes.set_yticklabels(('a', 'b', 'c', 'd', 'e'))
self.axes.set_xticks(range(0, 300, 60))
self.axes.set_xticklabels((u'周一', u'周二', u'周三', u'周四', u'周五'))
self.draw()
class MatplotlibWidget(QWidget):
def __init__(self, parent=None):
super(MatplotlibWidget, self).__init__(parent)
self.initUi()
def initUi(self):
self.layout = QVBoxLayout(self)
self.mpl = MyMplCanvas(self, width=5, height=4, dpi=100)
# 初始化显示甘特图
self.mpl.Display_dynamic_gantt()
self.layout.addWidget(self.mpl)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = MatplotlibWidget()
ui.show()
sys.exit(app.exec_())
代码呢,我只挑重要的讲,主要是为了给想快速实现的小白看的,没必要把全部代码搞懂!
首先,大家可以直接复制整个代码作为模板(因为我就是这样的嘻嘻),主要可以自行修改的部分有两个:启动显示动态图、绘制动态图方法函数,其余部分都可以不用管,直接用就是!
一是启动显示动态图部分,这个部分定义了一个函数Display_dynamic_gantt(),这个主要就是用来显示动态的图表,其中里面设置了一个QTimer对象,这个可以用来更新函数,timer.timeout.connect()就是用来连接需要更新的函数的, timer.start(1000)表示开始动态更新,每秒更新一次连接括号里的函数。
二是绘制动态图方法函数,这个部分定义了需要更新的函数update_figure(),也就是绘制动态甘特图的函数。这里我用到了datetime方法,它可以获取当前的系统时间,年月日、时分秒都可以,因为要实现更新,就得需要一个更新的条件,即每次调用都会产生不同的数据,那么最简单的方式就是获取系统时间了(有的人用的随机函数也可以,但是得到的数据是不确定的,所以不是很适用)。接着就是调用self.axes.clear(),这个很重要,因为你在每次绘制之前不清除上一次的结果,就会保留之前的绘制图表,结果可想而知!时间这里我获取的是秒,这样可以更新快一点。然后就是绘制图表的部分了,这里大家可以绘制自己想要的图表,我已甘特图为例,具体怎么画图的大家可以看我之前写的文章Matplotlib.pyplot中的冷门方法。我在甘特图的宽度上加了系统时间的秒数,所以每次更新该函数后都会重新绘制一次甘特图,而每一条的宽度就是当前的系统时间的秒的大小。同时我也给几个条形设置了不同的速度,比如l1就是1.8倍速,同时设置了范围不能超过60。
总之把想绘制的图像以及更新的效果设置好就了,运行结果如下,不过由于是截图所以不是动态的,实际效果是每个条形都会变化长度!好了,这部分就介绍到这,下一篇告诉大家怎么在ui文件中设置控件显示图表!