《Python Qt GUI与数据可视化编程》第14章“Matplotlib数据可视化”的示例程序是在Python 3.7和Matplotlib 3.0.0版本下测试过的,运行都没有问题。但是在使用高版本的 Matplotlib 3.3.2时,程序会出现一个严重错误,导致程序根本无法运行。
例如在运行14.1节的示例程序 Demo14_1GUI.py 时,出现如下的错误
Traceback (most recent call last):
File "G:\PyQt5Book\DemoV5WithoutCpp\chap14matplotlib\Demo14_1Basics\Demo14_1GUI.py", line 106, in <module>
form=QmyMainWindow() #创建窗体
File "G:\PyQt5Book\DemoV5WithoutCpp\chap14matplotlib\Demo14_1Basics\Demo14_1GUI.py", line 45, in __init__
self.__iniFigure() # 创建绘图系统,初始化窗口
File "G:\PyQt5Book\DemoV5WithoutCpp\chap14matplotlib\Demo14_1Basics\Demo14_1GUI.py", line 50, in __iniFigure
self.__fig=mpl.figure.Figure(figsize=(8, 5)) #单位英寸
AttributeError: module 'matplotlib' has no attribute 'figure'
这个示例只有一个程序文件,文件 Demo14_1GUI.py 的完整代码如下
# -*- coding: utf-8 -*-
## 程序文件: Demo14_1GUI.py
## 使用matplotlib 面向对象方法在GUI中绘图
import sys
import numpy as np
import matplotlib as mpl
from matplotlib.backends.backend_qt5agg import (FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import Qt
class QmyMainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent) #调用父类构造函数
self.setWindowTitle("Demo14_1, GUI中的matplotlib绘图")
## rcParams[]参数设置,以正确显示汉字
mpl.rcParams['font.sans-serif']=['KaiTi','SimHei'] #汉字字体
mpl.rcParams['font.size']=12 #字体大小
mpl.rcParams['axes.unicode_minus'] =False #正常显示符号
self.__iniFigure() # 创建绘图系统,初始化窗口
self.__drawFigure() # 绘图
##==========自定义函数=================
def __iniFigure(self): ##创建绘图系统,初始化窗口
self.__fig=mpl.figure.Figure(figsize=(8, 5)) #单位英寸
self.__fig.suptitle("plot in GUI application") #总的图标题
figCanvas = FigureCanvas(self.__fig) #创建FigureCanvas对象,必须传递一个Figure对象
naviToolbar=NavigationToolbar(figCanvas, self) #创建工具栏
naviToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.addToolBar(naviToolbar) #添加工具栏到主窗口
self.setCentralWidget(figCanvas)
def __drawFigure(self): ## 绘图
t = np.linspace(0, 10, 40)
y1=np.sin(t)
y2=np.cos(2*t)
ax1=self.__fig.add_subplot(1,2,1) #添加子图,ax1是 matplotlib.axes.Axes 类对象
ax1.plot(t,y1,'r-o',label="sin", linewidth=1, markersize=5) #绘制一条曲线
ax1.plot(t,y2,'b:',label="cos",linewidth=2) #绘制一条曲线
ax1.set_xlabel('X 轴') # X轴标题
ax1.set_ylabel('Y 轴',fontsize=14) # Y轴标题
ax1.set_xlim([0,10]) # X轴范围
ax1.set_ylim([-1.5,1.5]) # Y轴范围
ax1.set_title("曲线") # 子图标题
ax1.legend() # 自动创建图例
ax2=self.__fig.add_subplot(1,2,2) #添加子图,ax2是 matplotlib.axes.Axes 类对象
week=["Mon","Tue","Wed","Thur","Fri","Sat","Sun"]
sales=np.random.randint(200,400,7)
ax2.bar(week,sales) # 绘制柱状图
ax2.set_xlabel('week days') # X轴标题
ax2.set_ylabel('参观人数') # Y轴标题
ax2.set_title("柱状图") # 子图标题
## ============窗体测试程序 ================================
if __name__ == "__main__": #用于当前窗体测试
app = QApplication(sys.argv) #创建GUI应用程序
form=QmyMainWindow() #创建窗体
form.show()
sys.exit(app.exec_())
分析错误信息,错误是由函数__iniFigure()中的这行代码导致的
self.__fig=mpl.figure.Figure(figsize=(8, 5))
在Python shell中执行下面的命令,也出现错误
>>> import matplotlib as mpl
>>> a=mpl.figure.Figure()
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
a=mpl.figure.Figure()
AttributeError: module 'matplotlib' has no attribute 'figure'
>>>
而换做如下两种写法是不会出现错误的
>>> import matplotlib.figure as fig
>>> a=fig.Figure()
>>> from matplotlib.figure import Figure
>>> b=Figure()
>>>
而且,原来的文件 Demo14_1GUI.py在单步调试运行的时候不会出现错误,连续运行时就出错,这可能是Matplotlib新版本中的一个Bug。
为了避免出现错误,将程序做如下的修改,就是直接导入Figure,使用如下的语句
from matplotlib.figure import Figure
然后在创建Figure的实例时直接使用Figure(),即在函数__iniFigure()中创建self.__fig的语句修改为如下的形式
self.__fig=Figure(figsize=(8, 5))
这样修改后,程序运行就没有问题了,可以出现如图的界面。
本章其他示例中出现类似的问题都可以这么修改。下面是修改后的文件Demo14_1GUI.py前一部分的代码。
# -*- coding: utf-8 -*-
## 程序文件: Demo14_1GUI.py
## 使用matplotlib 面向对象方法在GUI中绘图
import sys
import numpy as np
import matplotlib as mpl
from matplotlib.figure import Figure #增加了这条语句
from matplotlib.backends.backend_qt5agg import (FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtCore import Qt
class QmyMainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent) #调用父类构造函数
self.setWindowTitle("Demo14_1, GUI中的matplotlib绘图")
## rcParams[]参数设置,以正确显示汉字
mpl.rcParams['font.sans-serif']=['KaiTi','SimHei'] #汉字字体
mpl.rcParams['font.size']=12 #字体大小
mpl.rcParams['axes.unicode_minus'] =False #正常显示符号
self.__iniFigure() # 创建绘图系统,初始化窗口
self.__drawFigure() # 绘图
##==========自定义函数=================
def __iniFigure(self): ##创建绘图系统,初始化窗口
self.__fig=Figure(figsize=(8, 5)) #修改了这条语句
self.__fig.suptitle("plot in GUI application") #总的图标题
figCanvas = FigureCanvas(self.__fig) #创建FigureCanvas对象,必须传递一个Figure对象
naviToolbar=NavigationToolbar(figCanvas, self) #创建工具栏
naviToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
self.addToolBar(naviToolbar) #添加工具栏到主窗口
self.setCentralWidget(figCanvas)