《Python Qt GUI與數據可視化編程》第14章「Matplotlib數據可視化」的示例程序是在Python 3.7和Matplotlib 3.0.0版本下測試過的,運行都沒有問題。可是在使用高版本的 Matplotlib 3.3.2時,程序會出現一個嚴重錯誤,致使程序根本沒法運行。python
例如在運行14.1節的示例程序 Demo14_1GUI.py 時,出現以下的錯誤shell
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()中的這行代碼致使的app
self.__fig=mpl.figure.Figure(figsize=(8, 5))
在Python shell中執行下面的命令,也出現錯誤dom
>>> 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))
這樣修改後,程序運行就沒有問題了,能夠出現如圖的界面。spa
本章其餘示例中出現相似的問題均可以這麼修改。下面是修改後的文件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)