2016-11-08 2 views
0

Ich versuche, ein Programm zu machen, in dem ich ein Hauptfenster und ein zweites Fenster habe. Das zweite Fenster sollte geöffnet werden, indem eine Check-Box im Hauptfenster aktiviert und durch Deaktivieren der Checkbox geschlossen wird.Erstellen eines Diagramms in einem zweiten Fenster mit Daten aus dem Hauptfenster

Das folgende minimale Beispiel funktioniert bereits gut (dank ImportanceOfBeingErnest!), Aber ich möchte den Pfeil (der, der bereits beim Ausführen des Beispiels gebogen ist) durch Drehen der SpinBox im Hauptfenster drehen.

Lösung: Siehe 5. Kommentar in der ersten Antwort!

 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

Was genau funktioniert nicht? Da Sie nie 'Kinematic' nennen, was würden Sie erwarten? Es scheint auch, dass "self.pos" nirgendwo wirklich definiert ist, also nehme ich an, dass "update_plot" nicht richtig funktioniert? – ImportanceOfBeingErnest

+0

Mischen Sie 'pyplot' nicht mit Ihrer eigenen Einbettung, da dies zu subtilen globalen Statusproblemen führen kann. Sie sollten Signal/Slots verwenden, um zwischen Ihren Klassen zu kommunizieren. – tacaswell

+0

@ImportanceOfBeingErnest: Ah Entschuldigung, ich habe eine Zeile vergessen (Zeile 67). Wenn ich versuche, es jetzt auszuführen, erhalte ich den Fehler "x_zero = self.pos [:, 0] TypeError: 'Funktion' Objekt ist nicht einfügbar". – Michael

Antwort

0

Hier ist ein Arbeitsbeispiel von dem, was ich denke, Sie versuchen zu erreichen.
Das Hauptfenster hat eine Drehbox und ein Kontrollkästchen. Sobald das Kontrollkästchen angeklickt ist, wird ein neues Fenster mit einem Plot angezeigt und eine Animation wird gestartet. Der aktuelle Wert und ein Array werden dem Plotfenster zugewiesen. Wenn Sie den Drehfeldwert ändern, während die Animation ausgeführt wird, wird sie aktualisiert. Wenn das Plot-Fenster geschlossen ist oder wenn das Kontrollkästchen deaktiviert ist, wird die Animation gestoppt (und gelöscht).

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_()) 

Da ich nicht sicher war, was Sie animieren möchten, änderte ich den Plot zu einem BarPlot, aber man kann es, was auch immer Sie brauchen, ändern zurück. Ich hoffe, das hilft.

+0

Danke für dieses Beispiel! Ich habe einige Änderungen in meinem Code von Ihrem Beispiel hinzugefügt und es funktioniert bereits besser. Aber es gibt nur eine (wichtige!) Sache: In Ihrem Beispiel gibt es die Funktion update_factor, die den Plot aktualisiert, wenn der spin.value geändert wird. Es gibt auch eine Berechnung in dieser Funktion ... Was ich will, ist, dass durch die Änderung des spin.value die Funktion kinematisch erneut ausgeführt wird (mit dem neuen spin.value) und der Rückgabewert von Kinematic als neuer Plot verwendet wird. Informationen (in diesem Fall ein neues self.pos). – Michael

+0

Ich möchte nur die gesamte Berechnung in der Hauptklasse (Newspeher) machen und die Unterklasse (Plot) nur zum Plotten verwenden. Danke noch einmal! – Michael

+0

Natürlich können Sie einen beliebigen Wert von kinematic() 'an Ihren Plot senden, indem Sie das' spin.valueChanged' Signal mit 'kinematic' verbinden und' Plot.pos' innerhalb der 'kinematic' Funktion aktualisieren. Brauchst du Hilfe oder war es nur ein Kommentar? – ImportanceOfBeingErnest

Verwandte Themen