先看看我们要实现的效果:
这是一个基于机器学习的数据分析结果展示,可以看到元素包括了坐标轴标注,两条折线和图例。
为了实现在PyQt中画图,我们用到了pyqtgraph这个绘图库,它是完全python实现的,与PyQt程序可以完美融合,并且具备很多优势:
- 拥有丰富的图形种类;
- 能够快速地实时更新绘图数据;
- 能够进行交互式的操作;
- 多种标记功能;
接下来进入正题,开始使用pyqtgraph来实现我们要的图形。
安装
PyQtGraph的安装很简单,使用pip就可以直接安装:
pip install pyqtgraph
PyQtGraph自带一个丰富的示例模块,我们在命令行中输入:
python -m pyqtgraph.examples
即可启动官方Demo集合,效果如下:
建议先看看效果,然后有需要的demo再把代码复制出来到pycharm之类的IDE编辑,这个软件里面的字体实在太难看了,直接在里面看得瞎了。
在PyQt中集成pyqtgraph图形
在PyQtGraph中,有几种绘制图形的方法:
- pyqtgraph.plot():创建一个新的绘图窗口来显示数据;
- PlotWidget.plot():将一组新的数据添加到现有的绘图小部件;
- PlotItem.plot():将一组新的数据添加到现有的绘图小部件;
- GraphicsLayout.addPlot():添加一个新的图形到一个图形层中;
根据PyQtGraph这几种绘图方式,我们在PyQt中可以在窗口部件中显示图形,也可以在一个新的窗口中显示图形。
我用的方法是通过Promote To ...
功能嵌入到QGraphicsView
组件里。
操作步骤如下:
- Designer中,创建一个QGraphicsView小部件(“Graphics View”类别下的“Display Widgets”)。
- 用鼠标右键单击QGraphicsView并选择““Promote To...”。
- 在“Promoted calss name”下,输入您希望使用的类名称(“PlotWidget”,“GraphicsLayoutWidget”等)。这里我选的是PlotWidget
- 在“Header file”下,输入“pyqtgraph”。
- 点击“Add”,然后点击“Promote”。
有关promoting widgets的更多信息,请参阅设计器文档。“VideoSpeedTest”和“ScatterPlotSpeedTest”示例都演示了如何使用pyui4或pyside-uic编译为.py模块的.ui文件。“designerExample”示例演示从.ui文件动态生成python类(不需要pyuic4 / pyside-uic)。
然后对生成的ui文件执行ui2py
转换操作,ui2py操作很简单,运行PyQt安装目录下的pyuic5.bat
,例如:
pyuic5.bat -o target.py from.ui
之后就可以把这个QGraphicsView
控件当成plotWidget
使用了。
开始画图
现在回到我们一开始要实现的效果,我们需要两条折线,X轴坐标都是一样的,那么需要两组y坐标,本例用到的坐标数据如下:
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80]
b = [9.8, 5.5, 4.5, 4.4, 4.4, 4.1, 4.1, 2.10, 2.10, 2.54, 2.59, 2.66, 3.30, 2.33, 2.23, 2.68, 2.33, 2.67, 2.90, 2.21, 2.56, 2.45, 1.23, 2.45, 2.67,
2.3, 2.87, 2.65, 1.05, 1.05, 1.05, 1.86, 1.32, 1.34, 2.45, 2.46, 1.11, 1.35, 1.21, 0.00, 0.47, 0.49, 0.50, 0.57, 0.98, 1.21,
1.35, 1.32, 1.30, 0.46, 0.35, 0.40, 1.41, 0.21, -0.58, -0.90, 0.35, -0.21, -0.30, 0.31, 0.94, 0.15, -0.60, -0.34, 0.56, 0.67, 1.95, 0.45, 1.65, 1.78, 1.34, 1.41, 1.03, 1.05, 0.87, 0.98, 1.25, 0.78, 0.91, 1.42, 1.20]
y = [9.8, 5.5, 4.2, 3.0, 2.8, 3.1, 3.19, 2.94, 2.97, 2.70, 2.45, 3.56, 2.20, 2.34, 2.00, 2.19, 1.73, 1.54, 1.61, 1.60, 1.60, 1.60, 1.60, 1.64, 1.30, 1.30, 1.30, 1.08, 1.21, 1.15, 0.76, 1.21, 1.21, 1.21, 1.21, 0.81, 0.81,
0.81, 0.81, 0.54, 0.59, 0.50, 1.21, 0.83, 1.00, 0.50, 0.50, 0.50, 0.50, 0.30, 0.30, 0.34, 0.24, 0.24,
0.24, 0.41, 0.41, 0.56, 0.56, 0.56, 0.56, 0.28, 0.76, 0.53, 0.43, 0.65, 0.50, 0.67, 0.33, 0.40, 0.45, 0.72, 0.68, 0.64, 0.60, 0.60, 0.33, 0.35, 0.51, 0.51, 0.58]
有了坐标,我们可以来试试画图了,在刚刚ui2py步骤生成的python文件里面写代码:
# 把graphicsView赋值给plotWidget变量
# 其实这一步可以省略的,不过我们为了可读性写了这一步
plotWidget = self.graphicsView
# 简单的调用画图功能
plotWidget.plot(dataset.x, dataset.y)
plotWidget.plot(dataset.x, dataset.b)
效果如下:
可以看到已经把两条折线画出来了,但是背景是黑色的,两条线没有区分颜色,坐标轴没有标注,图例也没有…… 别急,一步步来
设置背景颜色
刚才的代码,我们加上这一行:
# w 表示 white 白色
plotWidget.setBackground('w')
效果很明显,背景变成白色了
不过这还不够,每条线要有不同的颜色区分,继续
设置线条颜色
将之前的代码改为:
plotWidget.setBackground('w')
# 增加了 pen 参数
plotWidget.plot(dataset.x, dataset.y, pen=(1, 2))
plotWidget.plot(dataset.x, dataset.b, pen=(2, 2))
看看效果,可以看到线条的颜色已经变了
那么pen后面的参数是什么意思呢,根据文档,(1,2)
中的2代表有2条线,系统会自动创建两种不同的颜色,1就代表这是第一条线,使用第一种颜色~ 如果有你多条线,就把后面的数字改成线的数量就好啦~
如果把pen设置成None的话,就不会画线,变成画点。
设置坐标轴标签
在刚才代码的基础上,增加:
# 设置坐标坐标轴标签
plotWidget.setLabel('left', 'LOSS')
# 设置底部坐标轴标签
plotWidget.setLabel('bottom', 'epoch')
nice!标签出来了
接下来就是最后一步,设置图例了~
设置图例
根据文档,设置图例很简单,就是在画线的时候指定一个name参数就好了,代码如下:
# 先添加图例,不然不会显示
plotWidget.addLegend()
plotWidget.plot(dataset.x, dataset.y, pen=(1, 2), name='训练集')
plotWidget.plot(dataset.x, dataset.b, pen=(2, 2), name='测试集')
看看效果,终于完成了!图例也有了~
不过对比我们一开始的图好像还差了网格线,这个也很简单,设置一下属性就行:
plotWidget.showGrid(x=True, y=True)
完整代码
以下是本例子的完整代码:
plotWidget.addLegend()
plotWidget.setBackground('w')
plotWidget.plot(dataset.x, dataset.y, pen=(1, 2), name='训练集')
plotWidget.plot(dataset.x, dataset.b, pen=(2, 2), name='测试集')
plotWidget.setLabel('left', 'LOSS')
plotWidget.setLabel('bottom', 'epoch')
plotWidget.showGrid(x=True, y=True)
同学们可以根据自己的需要修改练习~
参考文档
如果想深入了解更多关于pyqtgraph的操作,可以参考以下文档,优先推荐读官方文档和Demo,非常丰富!
pyqtgraph会图库的官方文档:http://www.pyqtgraph.org/
不想看英文文档的小伙伴可以看看社区的翻译版中文文档:
- https://xiaozhuanlan.com/topic/0184539672
- https://blog.csdn.net/Eppley/article/details/82999998
- https://zmister.com/archives/187.html
欢迎交流
我整理了一系列的技术文章和资料,在公众号「程序设计实验室」后台回复 linux、flutter、c#、netcore、android、java、python 等可获取相关技术文章和资料,同时有任何问题都可以在公众号后台留言~