2013-08-15 3 views
6

Каков наилучший способ встраивания 3D-графика в графический интерфейс PySide? Я посмотрел на некоторые примеры здесь 2D графиков, внедренных в PySide GUI:Встроить интерактивный 3D-график в PySide

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

Однако функциональные возможности, что я ищу не совсем то же самое. Цифра должна вращаться и масштабироваться на основе ввода мыши от пользователя так же, как если бы она была нарисована в отдельном окне.

Я стараюсь избегать необходимости в ручном режиме и писать функции для преобразования мыши + перемещение в фигуру, поворот и перетяжку холста - даже если это единственный способ, я даже не уверен, как это сделать , Но я полагаю (ни каламбур не должен), что должен быть способ повторно использовать уже существующие функции для создания 3D-графиков в их собственных окнах.

Вот мой код. Он работает по назначению, но сюжет не является интерактивным. Любые советы приветствуются!

EDIT: Я исправил использование фигурыCanvas в соответствии с исправлениями tcaswell. Я также добавил немного из документации matplotlib Event Handling and Picking, чтобы показать, что фигура, похоже, получает события на mouseclick.

Окончательный Редактировать: Следующий код теперь производит участок по своему желанию.

# -*- 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

Вы смотрели на VPython? Я знаю, что он делает то, что вы ищете, но я раньше не пробовал встраивать его в графический интерфейс PySide. –

+0

Да, у меня есть. Я был очень впечатлен его силой и простотой - пять минут, и у меня была анимация шара, подпрыгивающего вверх и вниз с силой тяжести. Однако, изучив его немного больше, я не мог найти случаев, когда кто-то пытался внедрить его в PySide. – Bryant

+0

checkout, как это делает код базы данных 'qt4agg' – tacaswell

ответ

7

Вы не используете FigureCanvas права:

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

Каждый раз, когда вы назвали FigureCanvas(..) вы крепящий фигуру на новый холст (которые были не FigureCanvas вы видели), следовательно призывного спины никогда не стреляли (потому что они слушали FigureCanvas, которых вы не могли видеть).

+0

Спасибо, помощник. Я ценю помощь. Отредактировано исходное сообщение, чтобы включить ваши изменения; теперь он распечатывает информацию из события щелчка мыши, чтобы показать, что события действительно регистрируются. Однако он не поддерживает поворот и масштабирование. Это то, чего вы ожидали? Или я снова что-то испортил? haha – Bryant

+0

Если это решило проблему, которую вы задали в OP, вы должны принять ответ (большой серый флажок слева). Если у вас есть новые проблемы, вы должны задать новый вопрос. – tacaswell

+0

, а печать - из-за вашей функции 'on_click', которую вы регистрируете. Удалите это, и печать исчезнет. – tacaswell

1

1) Создайте FigureCanvas до, добавив оси. См https://stackoverflow.com/a/9007892/3962328

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

или

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) Попробуйте ax.mouse_init(), чтобы восстановить связь:

... 
ax = fig.gca(projection="3d") 
... 
canvas = FigureCanvas(fig) 
ax.mouse_init() 
Смежные вопросы