pyqt 5のUIにmatplotlibのパターンが埋め込まれてリアルタイムで更新されます。


一、pyqt 5のUIにmatplotlibを埋め込む方法
1、モジュールの導入
導入モジュールは簡単で、まずpyqt 5を使用すると宣言し、FigreCanvas QTAggを通じてカンバスを作成し、カンバスの画像をUIに表示することができます。pyqt 5のコントロールに相当します。後の図形はこのカンバスに構築されます。そして、このカンバスの中のpyqt 5のコントロールをpyqt 5のUIに追加します。ここで注意したいのは、matplotlib.figurのFigurではなく、matplotlib.pylotモジュールの中のFigurではないので、はっきり区別してください。

import matplotlib
matplotlib.use("Qt5Agg") #     pyqt5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg # pyqt5   
import matplotlib.pyplot as plt
# matplotlib.figure         Artist(           Artist   ),       plot  
from matplotlib.figure import Figure 
2、pyqt 5キャンバスを作成し、スタイルを簡単に設定する
キャンバスクラスを作成し、上から導入したFigreCanvas QTAggを継承し、Figureを通じてカンバスを作成し、パラメータとして親クラスFigreCanvas QTAggに渡す。このステップがないと、すべてが無駄になります。追加は成功しません。)最後のステップに図形描画エリアself.axesを追加します。

class MyMatplotlibFigure(FigureCanvasQTAgg):
  """
         ,      FigureCanvasQTAgg
  """
  def __init__(self, width=10, heigh=10, dpi=100):
    plt.rcParams['figure.facecolor'] = 'r' #       
    plt.rcParams['axes.facecolor'] = 'b' #        
    self.width = width
    self.heigh = heigh
    self.dpi = dpi
    self.figs = Figure(figsize=(self.width, self.heigh), dpi=self.dpi)
    super(MyMatplotlibFigure, self).__init__(self.figs) #       self.fig,         
    self.axes = self.figs.add_subplot(111)
3、布を作って掘る穴を埋める。
上のカスタムキャンバス類MyMatplotlibFigureは書いた時には間違いを指摘しませんが、絵を描く時には馬鹿になります。エラーがないので、フラッシュバックしました。そして不審なクラスと方法を一つずつtry…except…print、pythonに原因を教えてほしいです。すみません。結局何も得られませんでした。debugを使ってシングルステップで調整してゆっくり分析して、疲れきったステップで最後にキャンバスをpyqt 5に追加するのを見た時、モジュールbackend_にジャンプします。qt.5 pyファイルの500行目:if self.height()<0 or self.width()<0:debugの変数分析から見ました。
実はこれは簡単な間違いですが、気をつけないと検査が大変です。エラーの原因は、いくつかのプログラマがカスタムクラス内で外部からのパラメータを受信するときに、しばしば転送パラメータをグローバル変数に変換します。例えば、この例では初期化します。init_方法で受信した三つのパラメータwidth、heigh、dpiは、ついでに書きました。

self.width = width
self.heigh = heigh
self.dpi = dpi
 そして呼び出し!問題はここにあります。実は後ろから呼び出しがあってもなくても、フラッシュバックします。!!!!なぜですか?
FigreCanvas QTAgg親類にバックエンドを導入しましたので。qt 5 pyモジュール、backend_qt 5モジュールの内部にも同じ変数名self.widthとself.heighが使用されていますので、ここでは上の表記で親変数の上書きができます。正しい書き方:

class MyMatplotlibFigure(FigureCanvasQTAgg):
  """
         ,      FigureCanvasQTAgg
  """
  def __init__(self, width=10, heigh=10, dpi=100):
    plt.rcParams['figure.facecolor'] = 'r' #       
    plt.rcParams['axes.facecolor'] = 'b' #        
    #     Figure, Figure matplotlib  Figure,  matplotlib.pyplot   Figure
    #       ,width, heigh        ,   self.width、self.heigh      ,  self.width、self.heigh       FigureCanvasQTAgg     ,         
    self.figs = Figure(figsize=(width, heigh), dpi=dpi)
    super(MyMatplotlibFigure, self).__init__(self.figs) #       self.fig,         (          )
    self.axes = self.figs.add_subplot(111) #      
ここで直接に引用文字を使えばいいです。これらのパラメータは後から使えなくなります。使えば簡単に名前を変えます。例えば、self.w=width self.h=heigh=heigh
4、キャンバスをpyqt 5のUIに追加する。
ここでは比較的簡単になります。簡単なウィンドウを作成し、labelを追加し、上で作成したカスタム画布類を実例化し、変数self.canvasでインスタンスを受信します。これはpyqt 5のコントロールに相当します。labelでレイアウトを作成し、レイアウトに画布self.cvasを追加します。
この製図方法はどこに置いてもいいです。上のカスタムクラスにこの方法を追加することもできます。最後の製図の二行だけ簡単に修正すればいいです。

class MainDialogImgBW_(QtWidgets.QMainWindow):
  """
    UI   ,       。
  """
  def __init__(self):
    super(MainDialogImgBW_, self).__init__()
    self.setWindowTitle("  matplotlib")
    self.setObjectName("widget")
    self.resize(800, 600)
    self.label = QtWidgets.QLabel(self)
    self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
    self.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
    self.plotcos()
    self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
    self.hboxlayout.addWidget(self.canvas)

  def plotcos(self):
    # plt.clf()
    t = np.arange(0.0, 5.0, 0.01)
    s = np.cos(2 * np.pi * t)
    self.canvas.aexs.plot(t, s)
    self.canvas.figs.suptitle("sin") #     
二、リアルタイムでmatplotlib画像のピットを更新する
リアルタイムで画像を更新する場合は、ネットワークを通じて検索すると、ほぼ同じ結果が先にクリアされる前の画像、再plot、再描画DRaw()を加えて、他のスレッドから最も代表的な三部作の手順は以下の通りです。

self.axes.cla()
self.axes.plot(x, y, 'o',xx,yy)
self.draw()
 この三部作は間違いないですが、彼らが言っているのは簡単です。細かいところに注意が必要です。そうでなければ、同じように更新や誤報がないです。注意しなければならない穴はdrawです。彼らの書き込みは簡単なので、彼らのselfにいくつかの意味があるかどうかは分かりません。普通はこのように書くのは間違いです。cla()はクリアされています。グラフィックエリアは、plot()は再描画されています。これらはいずれも図形描画エリアの操作ですが、draw()を再描画するのは、キャンバス層が描画エリアではありません。しかもdrawだけでは足りないし、flashも必要です。events()がないとキャンバスの更新中に途中で偶然に退避する可能性があります。完全な正しいコードは以下の通りです。

class MyMatplotlibFigure(FigureCanvasQTAgg):
  """
         ,      FigureCanvasQTAgg
  """
  def __init__(self, width=10, heigh=10, dpi=100):
    plt.rcParams['figure.facecolor'] = 'r' #       
    plt.rcParams['axes.facecolor'] = 'b' #        
    #     Figure, Figure matplotlib  Figure,  matplotlib.pyplot   Figure
    self.figs = Figure(figsize=(width, heigh), dpi=dpi)
    super(MyMatplotlibFigure, self).__init__(self.figs) #       self.fig, 
    self.axes = self.figs.add_subplot(111) #      
  def mat_plot_drow_axes(self, t, s):
    """
                
    :return:
    """
    self.axes.cla() #      

    self.axes.spines['top'].set_visible(False) #       
    self.axes.spines['right'].set_visible(False) #       
    #    、    (0,0)   
    # self.axes.spines['bottom'].set_position(('data', 0)) #   y        0
    self.axes.spines['left'].set_position(('data', 0)) #   x        0
    self.axes.plot(t, s, 'o-r', linewidth=0.5)
    self.figs.canvas.draw() #          ,self.figs.canvas
    self.figs.canvas.flush_events() #     self.figs.canvas

class MainDialogImgBW(QtWidgets.QMainWindow):
  """
    UI   ,       。
  """
  def __init__(self):
    super(MainDialogImgBW_, self).__init__()
    self.setWindowTitle("  matplotlib")
    self.setObjectName("widget")
    self.resize(800, 600)
    self.label = QtWidgets.QLabel(self)
    self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
    self.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
    self.plotcos()
    self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
    self.hboxlayout.addWidget(self.canvas)

  def plotcos(self):
    # plt.clf()
    t = np.arange(0.0, 5.0, 0.01)
    s = np.cos(2 * np.pi * t)
    self.canvas.mat_plot_drow_axes(t, s)
    self.canvas.figs.suptitle("sin") #     


if __name__ == "__main__":
  app = QtWidgets.QApplication(sys.argv)
  main = MainDialogImgBW()
  main.show()
  sys.exit(app.exec_())
*注意すべき点はキャンバスの書き換えの書き方で、self.draw()でもself.axs.draw()でもないし、self.figs.draw()でもない、self.figs.cvas.draw()とself.figs.fs.flash()です。events()は、ここで比較的穴が空いているのは、この二つのコードを書く時にスマートアラームがありません。私が使っているpycharmは、この穴に穴ができたかもしれません。他のIDEが注意するかどうか分かりません。ここで注意するのはself.figs.cvas.draw()だけです。self.figs.cvas.flash。events()の時も描き直しますが、運行中にフラッシュバックする可能性がありますので、安全です。
三、リアルタイムでmatplotlibを更新する別の方法
上はaxs.claを使ってグラフを更新しますが、次の図は前のグラフとは全然違っています。キャンバスの背景色なども違っています。上のaxes.claを使って絵を整理するだけでは足りないです。キャンバスfigure.clfをきれいに整理してもらえばいいです。この場所はよく見てください。キャンバスを掃除するのはclfの一字の差です。もう一つの注意すべき点は、キャンバスを掃除した後、キャンバスの上の製図エリアaxesも掃除しました。もう一度axesを追加する必要があります。完全なコードは以下の通りです。

class MyMatplotlibFigure(FigureCanvasQTAgg):
  """
         ,      FigureCanvasQTAgg
  """
  def __init__(self, width=10, heigh=10, dpi=100):
    #     Figure, Figure matplotlib  Figure,  matplotlib.pyplot   Figure
    self.figs = Figure(figsize=(width, heigh), dpi=dpi)
    super(MyMatplotlibFigure, self).__init__(self.figs) #       self.fig, 
  def mat_plot_drow(self, t, s):
    """
                
    :return:
    """
    self.figs.clf() #     ,   clf()
    self.axes = self.figs.add_subplot(111) #               
 self.axes.patch.set_facecolor("#01386a") #   ax      
    self.axes.patch.set_alpha(0.5) #   ax         
    self.figs.patch.set_facecolor('#01386a') #         
    self.axes.spines['bottom'].set_color('r') #        
    self.axes.spines['top'].set_visible(False) #       
    self.axes.spines['right'].set_visible(False) #       
    #    、    (0,0)   
    # self.axes.spines['bottom'].set_position(('data', 0)) #   y        0
    self.axes.spines['left'].set_position(('data', 0)) #   x        0
    self.axes.plot(t, s, 'o-r', linewidth=0.5)
    self.figs.canvas.draw() #          ,self.figs.canvas
    self.figs.canvas.flush_events() #     self.figs.canvas

class MainDialogImgBW(QtWidgets.QMainWindow):
  """
    UI   ,       。
  """
  def __init__(self):
    super(MainDialogImgBW_, self).__init__()
    self.setWindowTitle("  matplotlib")
    self.setObjectName("widget")
    self.resize(800, 600)
    self.label = QtWidgets.QLabel(self)
    self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
    self.canvas = MyMatplotlibFigure(width=5, heigh=4, dpi=100)
    self.plotcos()
    self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
    self.hboxlayout.addWidget(self.canvas)

  def plotcos(self):
    # plt.clf()
    t = np.arange(0.0, 5.0, 0.01)
    s = np.cos(2 * np.pi * t)
    self.canvas.mat_plot_drow(t, s)
    self.canvas.figs.suptitle("sin") #     


if __name__ == "__main__":
  app = QtWidgets.QApplication(sys.argv)
  main = MainDialogImgBW()
  main.show()
  sys.exit(app.exec_())
四、animationの方式でmaplotlibを更新する。
もしUIの中で更新頻度が非常に高いならば、例えば株や先物のtickデータは上の更新方式はちょっと足りないです。更新もできますが、フラッシュ画面の状況がとても悪いかもしれません。高周波の更新はやはりアニメーション方式で更新します。
animationを使うには、matplotlib.animationモジュールを導入するFunncAnimation方法を追加する必要があります。すべての導入モジュールは以下の通りです。

import matplotlib
matplotlib.use("Qt5Agg") #     pyqt5
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg # pyqt5   
import matplotlib.pyplot as plt
from matplotlib.figure import Figure 
from matplotlib.animation import FuncAnimation
FunncAnimationの基礎はここで詳しく説明しません。フォーラム内で検索すれば見つけられます。ピットが存在する可能性があるところだけを紹介します。tick内のです。ここで直接コードを付けます。

class MyMatPlotAnimation(FigureCanvasQTAgg):
  """
         ,        (   )FigureCanvasQTAgg,        
  """
  def __init__(self, width=10, heigh=10, dpi=100):
    #     Figure, Figure matplotlib  Figure,  matplotlib.pyplot   Figure
    self.figs = Figure(figsize=(width, heigh), dpi=dpi)
    super(MyMatPlotAnimation, self).__init__(self.figs) 
    self.figs.patch.set_facecolor('#01386a') #         
    self.axes = self.figs.add_subplot(111)

  def set_mat_func(self, t, s):
    """
           
    """
    self.t = t
    self.s = s
    self.axes.cla()
    self.axes.patch.set_facecolor("#01386a") #   ax      
    self.axes.patch.set_alpha(0.5) #   ax         

    # self.axes.spines['top'].set_color('#01386a')
    self.axes.spines['top'].set_visible(False) #       
    self.axes.spines['right'].set_visible(False) #       

    self.axes.xaxis.set_ticks_position('bottom') #   ticks(  )      
    self.axes.yaxis.set_ticks_position('left') #   ticks(  )       
    #    、    (0,0)   
    # self.axes.spines['bottom'].set_position(('data', 0)) #   x   Y 0  
    self.axes.spines['left'].set_position(('data', 0)) #   y  x 0  
    self.plot_line, = self.axes.plot([], [], 'r-', linewidth=1) #   ‘,'    
    
  def plot_tick(self):
    plot_line = self.plot_line
    plot_axes = self.axes
    t = self.t
    
    def upgrade(i): #      plot_tick        
      x_data = [] #              self  ,           
      y_data = []
      for i in range(len(t)):
        x_data.append(i)
        y_data.append(self.s[i])
      plot_axes.plot(x_data, y_data, 'r-', linewidth=1)
      return plot_line, #       ‘,'    ,     
      
    ani = FuncAnimation(self.figs, upgrade, blit=True, repeat=False)
    self.figs.canvas.draw() #         

class MainDialogImgBW(QtWidgets.QMainWindow):
  def __init__(self):
    super(MainDialogImgBW_, self).__init__()
    self.setWindowTitle("  matplotlib")
    self.setObjectName("widget")
    self.resize(800, 600)
    self.label = QtWidgets.QLabel(self)
    self.label.setGeometry(QtCore.QRect(0, 0, 800, 600))
    self.canvas = MyMatPlotAnimation(width=5, heigh=4, dpi=100)
    self.plotcos()
    self.hboxlayout = QtWidgets.QHBoxLayout(self.label)
    self.hboxlayout.addWidget(self.canvas)

  def plotcos(self):
    t = np.arange(0.0, 5.0, 0.01)
    s = np.cos(2 * np.pi * t)
    self.canvas.set_mat_func(t, s)
    self.canvas.plot_tick()


if __name__ == "__main__":
  app = QtWidgets.QApplication(sys.argv)
  main = MainDialogImgBW()
  main.show()
  sys.exit(app.exec_())
ここで、pyqt 5のUIにmatplotlibのパターンを埋め込んでリアルタイムで更新した文章を紹介します。これに関連して、pyqt 5はmatplotlibのグラフィックコンテンツを埋め込みました。以前の記事を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。