2013-08-15 18 views
6

Qual è il modo migliore per incorporare un grafico 3D interattivo in una GUI PySide? Ho guardato alcuni esempi qui di grafici 2D incorporati in una GUI PySide:Incorporare un grafico 3D interattivo in PySide

Getting PySide to Work With Matplotlib
Matplotlib Interactive Graph Embedded In PyQt
Python/Matplotlib/Pyside Fast Timetrace Scrolling

Tuttavia, la funzionalità che sto cercando non è proprio la stessa cosa. La figura deve ruotare e ingrandire in base all'input del mouse dall'utente nello stesso modo in cui veniva disegnata in una finestra separata.

Sto cercando di evitare di dover entrare manualmente e scrivere le funzioni per trasformare il clic del mouse + spostare in una figura ruotata e ridipingere il quadro - anche se è l'unico modo, non sono nemmeno sicuro di come farlo . Ma immagino che non ci dovrebbe essere un modo per riutilizzare le funzionalità già presenti per la creazione di grafici 3D nelle proprie finestre.

Ecco il mio codice. Funziona come previsto, ma la trama non è interattiva. Qualche consiglio è apprezzato!

MODIFICA: Ho corretto l'uso di FigureCanvas in base alle correzioni di tcaswell. Ho anche aggiunto un po 'della documentazione di matplotlib Event Handling and Picking per mostrare che la figura sembra ricevere gli eventi sul mouseclick.

Modifica finale: Il seguente codice ora produce la trama come desiderato.

# -*- coding: utf-8 -*- 

from PySide import QtCore, QtGui 
import numpy as np 

import matplotlib 
import sys 
# specify the use of PySide 
matplotlib.rcParams['backend.qt4'] = "PySide" 

# import the figure canvas for interfacing with the backend 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg \ 
                   as FigureCanvas 

# import 3D plotting 
from mpl_toolkits.mplot3d import Axes3D # @UnusedImport 
from matplotlib.figure import Figure 


# Auto-generated code from QT Designer ---------------------------------------- 

class Ui_MainWindow(object): 
    def setupUi(self, MainWindow): 
     MainWindow.setObjectName("MainWindow") 
     MainWindow.resize(750, 497) 
     self.centralwidget = QtGui.QWidget(MainWindow) 
     self.centralwidget.setObjectName("centralwidget") 
     self.horizontalLayout_2 = QtGui.QHBoxLayout(self.centralwidget) 
     self.horizontalLayout_2.setObjectName("horizontalLayout_2") 
     self.frame_2 = QtGui.QFrame(self.centralwidget) 
     self.frame_2.setFrameShape(QtGui.QFrame.StyledPanel) 
     self.frame_2.setFrameShadow(QtGui.QFrame.Raised) 
     self.frame_2.setObjectName("frame_2") 
     self.verticalLayout = QtGui.QVBoxLayout(self.frame_2) 
     self.verticalLayout.setObjectName("verticalLayout") 
     self.label = QtGui.QLabel(self.frame_2) 
     self.label.setObjectName("label") 
     self.verticalLayout.addWidget(self.label) 
     self.label_2 = QtGui.QLabel(self.frame_2) 
     self.label_2.setObjectName("label_2") 
     self.verticalLayout.addWidget(self.label_2) 
     self.lineEdit = QtGui.QLineEdit(self.frame_2) 
     sizePolicy = QtGui.QSizePolicy(
          QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) 
     sizePolicy.setHorizontalStretch(0) 
     sizePolicy.setVerticalStretch(0) 
     sizePolicy.setHeightForWidth(
           self.lineEdit.sizePolicy().hasHeightForWidth()) 
     self.lineEdit.setSizePolicy(sizePolicy) 
     self.lineEdit.setObjectName("lineEdit") 
     self.verticalLayout.addWidget(self.lineEdit) 
     spacerItem = QtGui.QSpacerItem(
       20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) 
     self.verticalLayout.addItem(spacerItem) 
     self.horizontalLayout_2.addWidget(self.frame_2) 
     self.frame_plot = QtGui.QFrame(self.centralwidget) 
     self.frame_plot.setMinimumSize(QtCore.QSize(500, 0)) 
     self.frame_plot.setFrameShape(QtGui.QFrame.StyledPanel) 
     self.frame_plot.setFrameShadow(QtGui.QFrame.Raised) 
     self.frame_plot.setObjectName("frame_plot") 
     self.horizontalLayout_2.addWidget(self.frame_plot) 
     MainWindow.setCentralWidget(self.centralwidget) 

     self.retranslateUi(MainWindow) 
     QtCore.QMetaObject.connectSlotsByName(MainWindow) 

    def retranslateUi(self, MainWindow): 
     MainWindow.setWindowTitle(QtGui.QApplication.translate(
      "MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8)) 
     self.label.setText(QtGui.QApplication.translate("MainWindow", 
        "This is a qlabel.", None, QtGui.QApplication.UnicodeUTF8)) 
     self.label_2.setText(QtGui.QApplication.translate("MainWindow", 
      "And this is another one.", None, QtGui.QApplication.UnicodeUTF8)) 
     self.lineEdit.setText(QtGui.QApplication.translate("MainWindow", 
        "Text goes here.", None, QtGui.QApplication.UnicodeUTF8)) 

# Auto-generated code from QT Designer ---------------------------------------- 

class MainWindow(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainWindow, self).__init__(parent) 
     # intialize the window 
     self.ui = Ui_MainWindow() 
     self.ui.setupUi(self) 

     # create the matplotlib widget and put it in the frame on the right 
     self.ui.plotWidget = Mpwidget(parent=self.ui.frame_plot) 

class Mpwidget(FigureCanvas): 
    def __init__(self, parent=None): 

     self.figure = Figure(facecolor=(0, 0, 0)) 
     super(Mpwidget, self).__init__(self.figure) 
     self.setParent(parent) 

     # plot random 3D data 
     self.axes = self.figure.add_subplot(111, projection='3d') 
     self.data = np.random.random((3, 100)) 
     self.axes.plot(self.data[0, :], self.data[1, :], self.data[2, :]) 

if __name__ == "__main__": 
    app = QtGui.QApplication(sys.argv) 
    mw = MainWindow() 
    mw.show() 

    # adjust the frame size so that it fits right after the window is shown 
    s = mw.ui.frame_plot.size() 
    mw.ui.plotWidget.setGeometry(1, 1, s.width() - 2, s.height() - 2) 

    sys.exit(app.exec_()) 
+0

Hai guardato vpython? So che fa quello che stai cercando, ma non ho ancora provato a incorporarlo in una GUI PySide. –

+0

Sì, ho. Sono rimasto molto colpito dalla sua potenza e semplicità - cinque minuti, e ho avuto un'animazione di una palla che rimbalza su e giù con gravità. Tuttavia, dopo averlo cercato un po 'di più, non sono riuscito a trovare alcun caso in cui qualcuno abbia provato a incorporarlo in PySide. – Bryant

+0

verifica come il codice di backend 'qt4agg' fa questo – tacaswell

risposta

7

Non si sta utilizzando FigureCanvas destra:

class Mpwidget(FigureCanvas): 
    def __init__(self, parent=None): 
     self.figure = Figure(facecolor=(0, 0, 0)) 
     super(Mpwidget, self).__init__(self.figure) # this object _is_ your canvas 
     self.setParent(parent) 

     # plot random 3D data 
     self.axes = self.figure.add_subplot(111, projection='3d') 
     self.data = np.random.random((3, 100)) 
     self.axes.plot(self.data[0, :], self.data[1, :], self.data[2, :]) 

if __name__ == "__main__": 
    app = QtGui.QApplication(sys.argv) 
    mw = MainWindow() 
    mw.show() 

    # adjust the frame size so that it fits right after the window is shown 
    s = mw.ui.frame_plot.size() 
    mw.ui.plotWidget.setGeometry(1, 1, s.width() - 2, s.height() - 2) 

    sys.exit(app.exec_()) 

Ogni volta che hai chiamato FigureCanvas(..) si stava collegando la figura in una nuova tela (che non erano il FigureCanvas stavi vedendo) da qui il call-back non sparavano mai (perché stavano ascoltando su un FigureCanvas che non si vedeva).

+0

Grazie amico. Apprezzo l'aiuto. Modificato il post originale per includere le modifiche; ora stampa le informazioni dall'evento click del mouse per mostrare che gli eventi si registrano effettivamente. Tuttavia, non sembra supportare la rotazione e lo zoom fuori dalla scatola. È questo che ti aspettavi? Oppure ho rovinato qualcosa di nuovo? haha – Bryant

+0

Se questo problema è stato risolto nell'OP, è necessario accettare la risposta (grande casella di spunta grigia a sinistra). Se hai scoperto nuovi problemi dovresti fare una nuova domanda. – tacaswell

+0

e la stampa dipende dalla funzione 'on_click' che si registra. Rimuovilo e la stampa andrà via – tacaswell

1

1) Creare il FigureCanvas prima dello aggiungendo gli assi. Si veda https://stackoverflow.com/a/9007892/3962328

canvas = FigureCanvas(fig) 
ax = figure.add_subplot(111, projection='3d') 

o

class MyFigureCanvas(FigureCanvas): 
    def __init__(self): 
     self.figure = Figure() 
     super(FigureCanvas, self).__init__(self.figure) 
     self.axes = self.figure.add_subplot(111, projection='3d') 

2) Prova ax.mouse_init() per ripristinare la connessione:

... 
ax = fig.gca(projection="3d") 
... 
canvas = FigureCanvas(fig) 
ax.mouse_init() 
Problemi correlati