2016-11-08 13 views
0

メインウィンドウと2番目のウィンドウを持つプログラムを作成しようとしています。 2番目のウィンドウは、メインウィンドウのチェックボックスをチェックして開き、チェックを外して閉じます。メインウィンドウのデータを使用して2番目のウィンドウでプロットを作成する

以下の最小限の例はすでにうまく動作しています(ImportanceOfBeingErnest!のおかげで)、メインウィンドウのSpinBoxを変更して矢印(既に例を実行すると曲がっています)を回転します。

解決策:最初の回答の5番目のコメントを参照してください。

 import sys 
     from PyQt4 import QtGui, QtCore 

     from matplotlib import pyplot as plt 
     from mpl_toolkits.mplot3d import Axes3D 
     from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
     from matplotlib import animation 

     import numpy as np 


     class Newsphere(QtGui.QMainWindow): 

      def __init__(self): 
       super(Newsphere, self).__init__() 
       self.mainbox = QtGui.QWidget() 
       self.mainbox.setLayout(QtGui.QHBoxLayout()) 
       self.setCentralWidget(self.mainbox) 
       self.spin = QtGui.QSpinBox() 
       self.spin.setValue(20) 
       self.spin.setMaximum(100) 
       self.spin.setMinimum(-100) 
       self.checkPlot = QtGui.QCheckBox("Check") 
       self.mainbox.layout().addWidget(self.spin) 
       self.mainbox.layout().addWidget(self.checkPlot) 

       self.Plot = None 
       self.checkPlot.clicked.connect(self.showPlot) 

     def showPlot(self): 
      if self.Plot == None: 
       self.Plot = Plot(self.kinematic()) 
       self.Plot.show() 
       # register signal for closure 
       self.Plot.signalClose.connect(self.uncheck) 
       # register signal for spin value changed 
       self.spin.valueChanged.connect(self.kinematic) 
      else: 
       self.Plot.close() 
       self.Plot = None 

     def kinematic(self): 

      x = self.spin.value()/100 

      v = np.matrix([[1.,x,0.],[0.,1.,0.],[0.,0.,1.]]) 
      zero = np.matrix([[0.,0.,0.],[0.,0.,0.],[0.,0.,0.]]) 

      pos = np.hstack([v, zero]) 

      return pos 

     def uncheck(self): 
      self.checkPlot.setChecked(False) 
      self.Plot = None 

    class Plot(QtGui.QWidget): 

     signalClose = QtCore.pyqtSignal() 

     def __init__(self, pos=None): 
      super(Plot, self).__init__() 
      self.setLayout(QtGui.QHBoxLayout()) 

      self.fig = plt.figure() 
      self.ax = self.fig.add_subplot(111,projection = '3d') 
      self.fig.tight_layout() 
      self.ax.view_init(40, 225) 

      ''' dashed coordinate system ''' 
      self.ax.plot([0,1], [0,0], [0,0], label='$X_0$', linestyle="dashed", color="red") 
      self.ax.plot([0,0], [0,-10], [0,0], label='$Y_0$', linestyle="dashed", color="green") 
      self.ax.plot([0,0], [0,0], [0,1], label='$Z_0$', linestyle="dashed", color="blue") 

      self.ax.set_xlim3d(-3,3) 
      self.ax.set_ylim3d(-3,3) 
      self.ax.set_zlim3d(-3,3) 

      self.canvas = FigureCanvas(self.fig) 
      self.layout().addWidget(self.canvas) 

      self.pos = pos 

      self.setup_plot() 

      self.ani = animation.FuncAnimation(self.fig, self.update_plot, init_func=self.setup_plot, blit=True) 

     def setup_plot(self): 

      self.ax.legend(loc='best') 

      self.position = self.ax.quiver(0, 0, 0, 0, 0, 0, pivot="tail", color="black") 

      return self.position, 

     def update_plot(self, i): 

      x_zero = self.pos[:,3] 
      y_zero = self.pos[:,4] 
      z_zero = self.pos[:,5] 

      v_x = self.pos[0,0:3] 
      v_y = self.pos[1,0:3] 
      v_z = self.pos[2,0:3] 

      self.position = self.ax.quiver(-x_zero, -y_zero, z_zero, -v_x[0,:], v_y[0,:], v_z[0,:], pivot="tail", color="black") 
      self.canvas.draw() 

      return self.position, 

     # We need to make sure the animation stops, when the window is closed 
     def closeEvent(self, event): 
      self.signalClose.emit() 
      self.close() 
      super(Plot, self).closeEvent(event) 

     def close(self): 
      self.ani.event_source.stop() 
      super(Plot, self).close() 


    if __name__ == '__main__': 

     app = QtGui.QApplication(sys.argv) 
     main = Newsphere() 
     main.show() 
     sys.exit(app.exec_()) 
+0

正確には機能しません。あなたは実際に 'キネマティック'と呼ぶことはないので、あなたは何を期待していますか?また、 'self.pos'はどこにも定義されていないようですので、' update_plot'が正しく動作していないと思いますか? – ImportanceOfBeingErnest

+0

'pyplot'と自分の埋め込みを混在させないでください。微妙なグローバル状態の問題につながる可能性があります。クラス間で通信するには、信号/スロットを使用する必要があります。 – tacaswell

+0

@ImportanceOfBeingErnest:ああ、申し訳ありませんが、私は1行(行67)を忘れました。今すぐ実行しようとすると、エラーが発生します。 "x_zero = self.pos [:、0] TypeError: '関数'オブジェクトはサブスクリプトできません"。 – Michael

答えて

0

ここでは、私が達成しようとしていることの実例を示します。
メインウィンドウには、スピンボックスとチェックボックスがあります。チェックボックスをクリックすると、プロットのある新しいウィンドウが表示され、アニメーションが開始されます。現在の値と配列がプロットウィンドウに表示されます。アニメーションの実行中にスピンボックスの値を変更すると、その値が更新されます。プロットウィンドウが閉じている場合、またはチェックボックスがオフの場合、アニメーションは停止し、削除されます。

import sys 
from PyQt4 import QtGui, QtCore 

from matplotlib import pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas 
from matplotlib import animation 

import numpy as np 


class Newsphere(QtGui.QMainWindow): 

    def __init__(self): 
     super(Newsphere, self).__init__() 
     self.mainbox = QtGui.QWidget() 
     self.mainbox.setLayout(QtGui.QHBoxLayout()) 
     self.setCentralWidget(self.mainbox) 
     self.spin = QtGui.QSpinBox() 
     self.spin.setValue(5) 
     self.spin.setMaximum(10) 
     self.spin.setMinimum(1) 
     self.checkPlot = QtGui.QCheckBox("Check") 
     self.mainbox.layout().addWidget(self.spin) 
     self.mainbox.layout().addWidget(self.checkPlot) 

     self.Plot = None 
     self.checkPlot.clicked.connect(self.showPlot) 

    def showPlot(self): 
     if self.Plot == None: 
      self.Plot = Plot(self.kinematic(), self.spin.value()) 
      self.Plot.show() 
      # register signal for closure 
      self.Plot.signalClose.connect(self.uncheck) 
      # register signal for spin value changed 
      self.spin.valueChanged.connect(self.Plot.update_factor) 
     else: 
      self.Plot.close() 
      self.Plot = None 

    def kinematic(self): 
     v = np.array([[1.,2.,3.],[2.,1.,3.],[3.,2.,1.]]) 
     return v 

    def uncheck(self): 
     self.checkPlot.setChecked(False) 
     self.Plot = None 

class Plot(QtGui.QWidget): 

    signalClose = QtCore.pyqtSignal() 

    def __init__(self, v=None, factor=1): 
     super(Plot, self).__init__() 
     self.setLayout(QtGui.QHBoxLayout()) 

     self.fig = plt.figure() 
     self.ax = self.fig.add_subplot(111,projection = '3d') 
     self.ax.set_aspect('equal') 
     self.fig.tight_layout() 
     self.ax.view_init(40, 225) 

     self.ax.set_xlim3d(0,3) 
     self.ax.set_ylim3d(0,3) 
     self.ax.set_zlim3d(0,4) 

     self.canvas = FigureCanvas(self.fig) 
     self.layout().addWidget(self.canvas) 

     self.pos = v 

     self.setup_plot() 
     self.update_factor(factor) 

     self.ani = animation.FuncAnimation(self.fig, self.update_plot, blit=False) 

    def setup_plot(self): 
     xpos, ypos = np.meshgrid(np.arange(self.pos.shape[0]),np.arange(self.pos.shape[1])) 
     self.xpos = xpos.flatten('F') 
     self.ypos = ypos.flatten('F') 
     self.zpos = np.zeros_like(self.xpos) 
     self.bar = None 

    def update_factor(self, factor): 
     self.factor = factor 
     self.dx = np.ones_like(self.xpos)*np.min(np.abs(self.factor/10.), 0.1) 
     self.dy = self.dx.copy() 

    def update_plot(self, i): 

     if self.bar != None: 
      self.bar.remove() 
      del self.bar 
     pos = self.pos+np.sin(i/8.) 
     dz = pos.flatten() 

     self.bar = self.ax.bar3d(self.xpos, self.ypos, self.zpos, self.dx, self.dy, dz, 
         color=(1.-self.factor/10.,0,self.factor/10.), zsort='average', linewidth=0) 

     self.canvas.draw() 

    # We need to make sure the animation stops, when the window is closed 
    def closeEvent(self, event): 
     self.signalClose.emit() 
     self.close() 
     super(Plot, self).closeEvent(event) 

    def close(self): 
     self.ani.event_source.stop() 
     super(Plot, self).close() 


if __name__ == '__main__': 

    app = QtGui.QApplication(sys.argv)  
    main = Newsphere() 
    main.show() 
    sys.exit(app.exec_()) 

私はあなたがアニメーション化したいのかわからなかったので、私はbarplotにプロットを変更しましたが、あなたが戻って何が必要にそれを変更することができます。希望が役立ちます。

+0

この例をありがとう!あなたのコードからいくつかの変更を加えましたが、すでにうまく機能しています。しかし、あなたの例では、関数update_factorがあり、spin.valueが変更されたときにプロットが更新されます。この関数にはいくつかの計算があります...私が望むのは、spin.value関数のkinematicが(新しいspin.valueで)再び実行され、Kinematicからの戻り値が新しいplot-情報(この場合は新しいself.pos)。 – Michael

+0

私はメインクラス(Newspeher)ですべての計算を行い、作図のためにサブクラス(Plot)を使用したいだけです。再度、感謝します! – Michael

+0

'kinematic'に' spin.valueChanged'信号を接続し、 'kinematic'関数の中から' Plot.pos'を更新することで、 'kinematic()'の値をプロットに送ることができます。あなたはそれに助けが必要ですか、それとも単なるコメントですか? – ImportanceOfBeingErnest

関連する問題