Embed Interactive 3D Graphics in PySide

What is the best way to embed interactive 3D graphics in PySide's graphical interface? I reviewed some examples here of 2D graphs embedded in PySide GUI:

Getting PySide to work with Matplotlib
Integrated Matplotlib chart embedded in PyQt
Python / Matplotlib / Pyside Fast Timetrace Scrolling

However, the functionality I'm looking for is not exactly the same. The number should rotate and scale based on user input from the user just as if it were drawn in a separate window.

I try to avoid the need to manually and write functions to convert the mouse click + move to rotate the figure and drag the canvas - even if this is the only way, I don’t even know how to do it. But I don’t think that there should be a way to reuse existing functions to create 3D graphs in their own windows.

Here is my code. It works as intended, but the plot is not interactive. Any advice is appreciated!

EDIT: I fixed the use of FigureCanvas according to the tcaswell fixes. I also added a bit from the matplotlib document Handling events and assembly to show that the figure seems to be receiving events on mouseclick.

Final Edit: The following code now displays a graph as desired.

# -*- 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_()) 
+6
source share
2 answers

You are not using FigureCanvas on the right:

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

Each time you called FigureCanvas(..) , you attached the figure to a new canvas (which was not the FigureCanvas that you saw), so the callbacks never shot (because they were listening on the FigureCanvas that you couldn't see).

+7
source

1) Create a FigureCanvas before adding axes. See fooobar.com/questions/951829 / ...

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

or

 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) Try ax.mouse_init () to reconnect:

 ... ax = fig.gca(projection="3d") ... canvas = FigureCanvas(fig) ax.mouse_init() 
+1
source

Source: https://habr.com/ru/post/951827/


All Articles