python - PyQt5 中的 Mayavi 集成可能吗?
问题描述
是否可以将 mayavi 3d 绘图集成到使用 pyqt5 制作的 gui 中?在 mayavi 文档中,我发现了这个: http ://docs.enthought.com/mayavi/mayavi/building_applications.html但是当我运行代码时出现错误:“RuntimeError: No traitsui.toolkits plugin found for toolkit qt5”。
这是代码:
# First, and before importing any Enthought packages, set the ETS_TOOLKIT
# environment variable to qt4, to tell Traits that we will use Qt.
import os
os.environ['ETS_TOOLKIT'] = 'qt4'
# By default, the PySide binding will be used. If you want the PyQt bindings
# to be used, you need to set the QT_API environment variable to 'pyqt'
#os.environ['QT_API'] = 'pyqt'
# To be able to use PySide or PyQt4 and not run in conflicts with traits,
# we need to import QtGui and QtCore from pyface.qt
from pyface.qt import QtGui, QtCore
# Alternatively, you can bypass this line, but you need to make sure that
# the following lines are executed before the import of PyQT:
# import sip
# sip.setapi('QString', 2)
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, \
SceneEditor
################################################################################
#The actual visualization
class Visualization(HasTraits):
scene = Instance(MlabSceneModel, ())
@on_trait_change('scene.activated')
def update_plot(self):
# This function is called when the view is opened. We don't
# populate the scene when the view is not yet open, as some
# VTK features require a GLContext.
# We can do normal mlab calls on the embedded scene.
self.scene.mlab.test_points3d()
# the layout of the dialog screated
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
resizable=True # We need this to resize with the parent widget
)
################################################################################
# The QWidget containing the visualization, this is pure PyQt4 code.
class MayaviQWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.visualization = Visualization()
# If you want to debug, beware that you need to remove the Qt
# input hook.
#QtCore.pyqtRemoveInputHook()
#import pdb ; pdb.set_trace()
#QtCore.pyqtRestoreInputHook()
# The edit_traits call will generate the widget to embed.
self.ui = self.visualization.edit_traits(parent=self,
kind='subpanel').control
layout.addWidget(self.ui)
self.ui.setParent(self)
if __name__ == "__main__":
# Don't create a new QApplication, it would unhook the Events
# set by Traits on the existing QApplication. Simply use the
# '.instance()' method to retrieve the existing one.
app = QtGui.QApplication.instance()
container = QtGui.QWidget()
container.setWindowTitle("Embedding Mayavi in a PyQt4 Application")
# define a "complex" layout to test the behaviour
layout = QtGui.QGridLayout(container)
# put some stuff around mayavi
label_list = []
for i in range(3):
for j in range(3):
if (i==1) and (j==1):continue
label = QtGui.QLabel(container)
label.setText("Your QWidget at (%d, %d)" % (i,j))
label.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
layout.addWidget(label, i, j)
label_list.append(label)
mayavi_widget = MayaviQWidget(container)
layout.addWidget(mayavi_widget, 1, 1)
container.show()
window = QtGui.QMainWindow()
window.setCentralWidget(container)
window.show()
# Start the main event loop.
app.exec_()
解决方案
是的,可以将 mayavi 3d 绘图集成到使用 pyqt5 制作的 gui 中。不仅情节还可以显示动画!通过在 GUI 中的任何位置嵌入 mayavi 场景,几乎可以在 PyQt5 Gui 中完成您对单独的 Mayavi 窗口所做的一切。
如果您的代码与此链接完全相同:Qt 嵌入示例。然后尝试在单独的文件中运行此代码,它应该可以工作。如果不是,您必须正确重新安装库。
您可以参考下面的代码(更简单的版本)在您的 GUI 中嵌入 mayavi:
from PyQt5 import QtWidgets
import os
import numpy as np
from numpy import cos
from mayavi.mlab import contour3d
os.environ['ETS_TOOLKIT'] = 'qt4'
from pyface.qt import QtGui, QtCore
from traits.api import HasTraits, Instance, on_trait_change
from traitsui.api import View, Item
from mayavi.core.ui.api import MayaviScene, MlabSceneModel, SceneEditor
## create Mayavi Widget and show
class Visualization(HasTraits):
scene = Instance(MlabSceneModel, ())
@on_trait_change('scene.activated')
def update_plot(self):
## PLot to Show
x, y, z = np.ogrid[-3:3:60j, -3:3:60j, -3:3:60j]
t = 0
Pf = 0.45+((x*cos(t))*(x*cos(t)) + (y*cos(t))*(y*cos(t))-(z*cos(t))*(z*cos(t)))
obj = contour3d(Pf, contours=[0], transparent=False)
view = View(Item('scene', editor=SceneEditor(scene_class=MayaviScene),
height=250, width=300, show_label=False),
resizable=True )
class MayaviQWidget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
layout = QtGui.QVBoxLayout(self)
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
self.visualization = Visualization()
self.ui = self.visualization.edit_traits(parent=self,
kind='subpanel').control
layout.addWidget(self.ui)
self.ui.setParent(self)
#### PyQt5 GUI ####
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
## MAIN WINDOW
MainWindow.setObjectName("MainWindow")
MainWindow.setGeometry(200,200,1100,700)
## CENTRAL WIDGET
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
## GRID LAYOUT
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
## BUTTONS
self.button_default = QtWidgets.QPushButton(self.centralwidget)
self.button_default.setObjectName("button_default")
self.gridLayout.addWidget(self.button_default, 0, 0, 1,1)
self.button_previous_data = QtWidgets.QPushButton(self.centralwidget)
self.button_previous_data.setObjectName("button_previous_data")
self.gridLayout.addWidget(self.button_previous_data, 1, 1, 1,1)
## Mayavi Widget 1
container = QtGui.QWidget()
mayavi_widget = MayaviQWidget(container)
self.gridLayout.addWidget(mayavi_widget, 1, 0,1,1)
## Mayavi Widget 2
container1 = QtGui.QWidget()
mayavi_widget = MayaviQWidget(container1)
self.gridLayout.addWidget(mayavi_widget, 0, 1,1,1)
## SET TEXT
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Simulator"))
self.button_default.setText(_translate("MainWindow","Default Values"))
self.button_previous_data.setText(_translate("MainWindow","Previous Values"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
app.setStyle('Fusion')
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
尝试在专用控制台中运行此代码。希望这会帮助你。
推荐阅读
- git - 克隆/签出特定目录
- python - 将变量作为参数传递给 read_csv?
- python-3.x - 如何像一组命令一样逐行读取文本文件
- google-drive-api - 是否有 API 调用将文件从一个团队云端硬盘移动到另一个?
- c# - 如何使用 user32.dll 捕捉鼠标离开事件
- javascript - 三.JS和WebGL纹理自动resize
- c - C - 结构的指针数组添加 3 个项目,然后添加的每个新项目将除前 2 个之外的先前项目清空
- tsql - 何时调用 UPDATE STATISTICS 更好?在 COMMIT TRANS 之前或之后
- r - 在R列表中的两个字符串之间提取单词和/或字符串
- c++ - 初学者的 C++:如何将列表作为函数参数传递?