Python 2.7 使用mlab_source.reset进行数据更新时Python Enthound Mayavi崩溃
我正在尝试更新mayavi 3D绘图中的数据。数据的某些更改不会影响数据形状,因此可以使用mlab_source.set()方法(更新基础数据并刷新显示,而无需重置相机、重新生成VTK管道、重新生成基础数据结构等)。这是动画或快速绘图更新的最佳情况 如果基础数据改变了形状,文档建议使用mlab_source.reset()方法,该方法虽然不会重新创建整个管道或弄乱当前场景的摄影机,但确实会导致重建数据结构,从而导致一些性能开销。这会导致崩溃 最糟糕的方法是完全删除打印源,并通过新调用mlab.mesh()或任何用于打印数据的函数生成新的打印源。这将重新创建新的VTK管道、新的数据结构,并重置场景的视图(丢失当前的缩放和相机设置,这可能导致无法根据应用程序进行平滑交互) 我已经从我的应用程序中演示了一个简单的示例,其中一个球体类可以操纵其属性(位置、大小和分辨率)。更改位置和大小会导致坐标刷新,但数据大小保持不变。但是,更改分辨率会影响用于表示球体的纬度和经度细分的数量,从而更改坐标的数量。尝试使用“重置”时函数,解释器完全崩溃。我很确定这是基于网络上类似错误的VTK代码中的C级SEGFULT。似乎表明核心开发人员在大约5年前处理过这个问题,但我无法判断它是否真的得到了解决 我使用的是Mayavi 4.3.1,我使用的是Python(x,y)的Enthow工具套件。我使用的是Windows 7 64位Python 2.7.5。我使用的是PySide,但我删除了这些调用,并让mlab在本例中自行工作 下面是我的示例,它显示了mlab_source.set()正在工作,但在mlab_source.reset()上崩溃。您对它崩溃的原因有何想法?其他人是否可以复制它?我非常确定有其他方法可以通过源(TVTK)更新数据对象,但我在文档中找不到它,而且与特征相关的几十个属性很难浏览 感谢您的帮助Python 2.7 使用mlab_source.reset进行数据更新时Python Enthound Mayavi崩溃,python-2.7,segmentation-fault,enthought,mayavi,mayavi.mlab,Python 2.7,Segmentation Fault,Enthought,Mayavi,Mayavi.mlab,我正在尝试更新mayavi 3D绘图中的数据。数据的某些更改不会影响数据形状,因此可以使用mlab_source.set()方法(更新基础数据并刷新显示,而无需重置相机、重新生成VTK管道、重新生成基础数据结构等)。这是动画或快速绘图更新的最佳情况 如果基础数据改变了形状,文档建议使用mlab_source.reset()方法,该方法虽然不会重新创建整个管道或弄乱当前场景的摄影机,但确实会导致重建数据结构,从而导致一些性能开销。这会导致崩溃 最糟糕的方法是完全删除打印源,并通过新调用mlab.m
#Numpy Imports
from time import sleep
import numpy as np
from numpy import sin, cos, pi
class Sphere(object):
"""
Class for a sphere
"""
def __init__(self, c=None, r=None, n=None):
#Initial defaults
self._coordinates = None
self._c = np.array([0.0, 0.0, 0.0])
self._r = 1.0
self._n = 20
self._hash = []
self._required_inputs = [('c', list),
('r', float)]
#Assign Inputs
if c is not None:
self.c = c
else:
self.c = self._c
if r is not None:
self.r = r
else:
self.r = self._r
if n is not None:
self.n = n
else:
self.n = self._n
@property
def c(self):
"""
Center point of sphere
- Point is specified as a cartesian coordinate triplet, [x, y, z]
- Coordinates are stored as a numpy array
- Coordinates input as a list will be coerced to a numpy array
"""
return self._c
@c.setter
def c(self, val):
if isinstance(val, list):
val = np.array(val)
self._c = val
@property
def r(self):
"""
Radius of sphere
"""
return self._r
@r.setter
def r(self, val):
if val < 0:
raise ValueError("Sphere radius input must be positive")
self._r = val
@property
def n(self):
"""
Resolution of curvature
- Number of points used to represent circles and arcs
- For a sphere, n is the number of subdivisions per hemisphere (in both latitude and longitude)
"""
return self._n
@n.setter
def n(self, val):
if val < 0:
raise ValueError("Sphere n-value for specifying arc/circle resolution must be positive")
self._n = val
@property
def coordinates(self):
"""
Returns x, y, z coordinate arrays to visualize the shape in 3D
"""
self._lazy_update()
return self._coordinates
def _lazy_update(self):
"""
Only update the coordinates data if necessary
"""
#Get a newly calculated hash based on the sphere's inputs
new_hash = self._get_hash()
#Get the old hash
old_hash = self._hash
#Check if the sphere's state has changed
if new_hash != old_hash:
#Something changed - update the coordinates
self._update_coordinates()
def _get_hash(self):
"""
Get the sphere's inputs as an immutable data structure
"""
return tuple(map(tuple, [self._c, [self._r, self._n]]))
def _update_coordinates(self):
"""
Calculate 3D coordinates to represent the sphere
"""
c, r, n = self._c, self._r, self._n
#Get the angular distance between latitude and longitude lines
dphi, dtheta = pi / n, pi / n
#Generate a latitude and longitude grid
[phi, theta] = np.mgrid[0:pi + dphi*1.0:dphi,
0:2 * pi + dtheta*1.0:dtheta]
#Map the latitude longitude grid into cartesian x, y, z coordinates
x = c[0] + r * cos(phi) * sin(theta)
y = c[1] + r * sin(phi) * sin(theta)
z = c[2] + r * cos(theta)
#Store the coordinates
self._coordinates = x, y, z
#Update the hash to coordinates to these coordinates
self._hash = self._get_hash()
if __name__ == '__main__':
from mayavi import mlab
#Make a sphere
sphere = Sphere()
#Plot the sphere
source = mlab.mesh(*sphere.coordinates, representation='wireframe')
#Get the mlab_source
ms = source.mlab_source
#Increase the sphere's radius by 2
sphere.r *= 2
#New coordinates (with larger radius)
x, y, z = sphere.coordinates
#Currently plotted coordinates
x_old, y_old, z_old = ms.x, ms.y, ms.z
#Verify that new x, y, z are all same shape as old x, y, z
data_is_same_shape = all([i.shape == j.shape for i, j in zip([x_old, y_old, z_old], [x, y, z])])
#Pause to see the old sphere
sleep(2)
#Check if data has changed shape... (shouldn't have)
if data_is_same_shape:
print "Updating same-shaped data"
ms.set(x=x, y=y, z=z)
else:
print "Updating with different shaped data"
ms.reset(x=x, y=y, z=z)
#Increase the arc resolution
sphere.n = 50
#New coordinates (with more points)
x, y, z = sphere.coordinates
#Currently plotted coordinates
x_old, y_old, z_old = ms.x, ms.y, ms.z
#Verify that new x, y, z are all same shape as old x, y, z
data_is_same_shape = all([i.shape == j.shape for i, j in zip([x_old, y_old, z_old], [x, y, z])])
#Pause to see the bigger sphere
sleep(2)
#Check if data has changed shape... (should have this time...)
if data_is_same_shape:
print "Updating same-shaped data"
ms.set(x=x, y=y, z=z)
else:
#This is where the segfault / crash occurs
print "Updating with different shaped data"
ms.reset(x=x, y=y, z=z)
mlab.show()
直接修改TVTK Polydata对象似乎有一定的效果。它似乎在更新点,而没有自动修复连接,这就是为什么我还必须运行mlab_source.reset()。我假设reset()现在可以工作了,因为输入的数据具有相同数量的点,并且mlab_源处理自动生成连接数据。当减少点的数量时,它仍然会崩溃,可能是因为存在不存在的点的连接数据?我仍然对此感到非常失望
编辑3:
我已经实现了蛮力方法,仅从mlab.mesh()生成一个新曲面。为了防止重置视图,我禁用渲染并存储摄影机设置,然后在mlab.mesh()之后恢复摄影机设置,然后重新启用渲染。似乎工作得够快-仍然希望可以使用reset()更新基础数据
下面是我用来管理绘图对象的整个类(在进行编辑后响应GUI信号)
reset
有时会出现错误。您的所有调试方法看起来都在正确的轨道上。我认为应该可以在tvtk级别调整数据的形状,但您必须修改vtk源的多个字段(正如您在一个解决方案中指出的)。感谢您的肯定!在我看到或听到更好的解决方案或遇到性能问题之前,我将坚持使用“new_source”方法。如果我能想出如何在python中实现reset()在tvtk级别所做的事情,我会这么做,但我没能想出办法。
p = np.array([x.flatten(), y.flatten(), z.flatten()]).T
ms.dataset.points = p
ms.dataset.point_data.scalars = np.zeros(x.shape)
ms.dataset.points.modified()
#Regenerate the data structure
ms.reset(x=x, y=y, z=z)
class PlottablePrimitive(QtCore.QObject):
def __init__(self, parent=None, shape=None, scene=None, mlab=None):
super(PlottablePrimitive, self).__init__(parent=parent)
self._shape = None
self._scene = None
self._mlab = None
self._source = None
self._color = [0.706, 0.510, 0.196]
self._visible = True
self._opacity = 1.0
self._camera = {'position': None,
'focal_point': None,
'view_angle': None,
'view_up': None,
'clipping_range': None}
if shape is not None:
self._shape = shape
if scene is not None:
self._scene = scene
if mlab is not None:
self._mlab = mlab
@property
def shape(self):
return self._shape
@shape.setter
def shape(self, val):
self._shape = val
@property
def color(self):
return self._color
@color.setter
def color(self, color):
self._color = color
if self._source is not None:
surface = self._source.children[0].children[0].children[0]
surface.actor.mapper.scalar_visibility = False
surface.actor.property.color = tuple(color)
def plot(self):
x, y, z = self._shape.coordinates
self._source = self._mlab.mesh(x, y, z)
def update_plot(self):
ms = self._source.mlab_source
x, y, z = self._shape.coordinates
a, b, c = ms.x, ms.y, ms.z
data_is_same_shape = all([i.shape == j.shape for i, j in zip([a, b, c], [x, y, z])])
if data_is_same_shape:
print "Same Data Shape... updating"
#Update the data in-place
ms.set(x=x, y=y, z=z)
else:
print "New Data Shape... resetting data"
method = 'new_source'
if method == 'tvtk':
#Modify TVTK directly
p = np.array([x.flatten(), y.flatten(), z.flatten()]).T
ms.dataset.points = p
ms.dataset.point_data.scalars = np.zeros(x.shape)
ms.dataset.points.modified()
#Regenerate the data structure
ms.reset(x=x, y=y, z=z)
elif method == 'reset':
#Regenerate the data structure
ms.reset(x=x, y=y, z=z)
elif method == 'new_source':
scene = self._scene
#Save camera settings
self._save_camera()
#Disable rendering
self._scene.disable_render = True
#Delete old plot
self.delete_plot()
#Generate new mesh
self._source = self._mlab.mesh(x, y, z)
#Reset camera
self._restore_camera()
self._scene.disable_render = False
def _save_camera(self):
scene = self._scene
#Save camera settings
for setting in self._camera.keys():
self._camera[setting] = getattr(scene.camera, setting)
def _restore_camera(self):
scene = self._scene
#Save camera settings
for setting in self._camera.keys():
if self._camera[setting] is not None:
setattr(scene.camera, setting, self._camera[setting])
def delete_plot(self):
#Remove
if self._source is not None:
self._source.remove()
self._source = None