Reputation: 67
I've started using mayavi and I am trying to plot a voxel grid. For this I am using mlab.plot3d to plot each line of the grid, what makes the program very slow since the render has to be called for each line. Is there a way to plot all the lines by calling mlab.plot3d just once ? The main problem is that the lines I am plotting are disconnected, if I put one line after the other in the same array, the render is going to plot connections that I don't want. I've tried to connect the two non-connected lines by putting a None between both lines:
lines = [0.0, 3.0, None, 0.0, 6.0]
But this does not work.
My function to plot the grid line by line can be seen below:
def draw_voxel_grid_bbox_translated(voxel_grid, tube_radius=0.01, color=(0,0,0)):
'''
Draw a bounding box that shows the dimensions of the complete voxel grid in passed color
:param voxel_grid: The voxel grid used to draw the bounding box
:return: None
'''
# Drawing lines parallel to x axis
sense_change_z = 0
for z_step in range(2):
sense_change_y = 0
for y_step in range(2):
if sense_change_y == 0:
xs = [voxel_grid.min_grid_x - voxel_grid.min_grid_x, voxel_grid.max_grid_x - voxel_grid.min_grid_x]
sense_change_y = 1
else:
xs = [voxel_grid.max_grid_x - voxel_grid.min_grid_x, voxel_grid.min_grid_x - voxel_grid.min_grid_x]
sense_change_y = 0
if y_step == 0:
y_coord = voxel_grid.min_grid_y
else:
y_coord = voxel_grid.max_grid_y
if z_step == 0:
z_coord = voxel_grid.min_grid_z
else:
z_coord = voxel_grid.max_grid_z
ys = [y_coord - voxel_grid.min_grid_y, y_coord - voxel_grid.min_grid_y]
zs = [z_coord - voxel_grid.min_grid_z, z_coord - voxel_grid.min_grid_z]
mlab.plot3d(xs, ys, zs, color=color, tube_radius=tube_radius)
# Drawing lines parallel to y axis
for x_step in range(2):
for z_step in range(2):
ys = [voxel_grid.min_grid_y - voxel_grid.min_grid_y, voxel_grid.max_grid_y - voxel_grid.min_grid_y]
if x_step == 0:
x_coord = voxel_grid.min_grid_x
else:
x_coord = voxel_grid.max_grid_x
if z_step == 0:
z_coord = voxel_grid.min_grid_z
else:
z_coord = voxel_grid.max_grid_z
xs = [x_coord - voxel_grid.min_grid_x, x_coord - voxel_grid.min_grid_x]
zs = [z_coord - voxel_grid.min_grid_z, z_coord - voxel_grid.min_grid_z]
mlab.plot3d(xs, ys, zs, color=color, tube_radius=tube_radius)
# Drawing lines parallel to z axis
for x_step in range(2):
for y_step in range(2):
zs = [voxel_grid.min_grid_z - voxel_grid.min_grid_z, voxel_grid.max_grid_z - voxel_grid.min_grid_z]
if x_step == 0:
x_coord = voxel_grid.min_grid_x
else:
x_coord = voxel_grid.max_grid_x
if y_step == 0:
y_coord = voxel_grid.min_grid_y
else:
y_coord = voxel_grid.max_grid_y
xs = [x_coord - voxel_grid.min_grid_x, x_coord - voxel_grid.min_grid_x]
ys = [y_coord - voxel_grid.min_grid_y, y_coord - voxel_grid.min_grid_y]
mlab.plot3d(xs, ys, zs, color=color, tube_radius=tube_radius)
Upvotes: 1
Views: 1017
Reputation: 51
I meet the same situation. Finally, I use mlab.quiver3d
to solve this problem. Here is my solution.. Not only is it simpler and fast, but you can control the color of each line segmention individually! (In the code of this solution, I can assign the color of each box.)
Upvotes: 2
Reputation: 67
Thanks to @Jannick for the answer.
Here is the new function in case someone is interested:
def draw_voxel_grid_cells(voxel_grid):
# Array for the points with the shape of the total number of points needed to define for drawing all the lines of the grid
points = np.zeros((((voxel_grid.nbr_cells_z+1)*(voxel_grid.nbr_cells_y+1) + (voxel_grid.nbr_cells_z+1)*(voxel_grid.nbr_cells_x+1) + (voxel_grid.nbr_cells_y+1)*(voxel_grid.nbr_cells_x+1))*2, 3))
i = 0
# Drawing lines parallel to x axis
for z_step in range(voxel_grid.nbr_cells_z+1):
for y_step in range(voxel_grid.nbr_cells_y+1):
points[i,:] = [voxel_grid.min_grid_x, voxel_grid.min_grid_y+(voxel_grid.resolution*y_step), voxel_grid.min_grid_z+(voxel_grid.resolution*z_step)]
points[i+1, :] = [voxel_grid.max_grid_x, voxel_grid.min_grid_y+(voxel_grid.resolution*y_step), voxel_grid.min_grid_z+(voxel_grid.resolution*z_step)]
i += 2
# Drawing lines parallel to y axis
for z_step in range(voxel_grid.nbr_cells_z+1):
for x_step in range(voxel_grid.nbr_cells_x+1):
points[i,:] = [voxel_grid.min_grid_x+(voxel_grid.resolution*x_step), voxel_grid.min_grid_y, voxel_grid.min_grid_z+(voxel_grid.resolution*z_step)]
points[i+1, :] = [voxel_grid.min_grid_x+(voxel_grid.resolution*x_step), voxel_grid.max_grid_y, voxel_grid.min_grid_z+(voxel_grid.resolution*z_step)]
i += 2
# Drawing lines parallel to z axis
for y_step in range(voxel_grid.nbr_cells_y+1):
for x_step in range(voxel_grid.nbr_cells_x+1):
points[i,:] = [voxel_grid.min_grid_x+(voxel_grid.resolution*x_step), voxel_grid.min_grid_y+(voxel_grid.resolution*y_step), voxel_grid.min_grid_z]
points[i+1, :] = [voxel_grid.min_grid_x+(voxel_grid.resolution*x_step), voxel_grid.min_grid_y+(voxel_grid.resolution*y_step), voxel_grid.max_grid_z]
i += 2
connections = np.arange(0, ((voxel_grid.nbr_cells_z+1)*(voxel_grid.nbr_cells_y+1) + (voxel_grid.nbr_cells_z+1)*(voxel_grid.nbr_cells_x+1) + (voxel_grid.nbr_cells_y+1)*(voxel_grid.nbr_cells_x+1))*2)
connections = tuple(connections.reshape(-1,2))
# Plotting -------------------------------------------------
mlab.figure()
pts = mlab.points3d(points[:, 0], points[:, 1], points[:, 2], scale_factor=0.0001, color=(1, 0, 0))
pts.mlab_source.dataset.lines = np.array(connections)
tube = mlab.pipeline.tube(pts, tube_radius=0.001)
tube.filter.radius_factor = 1.
mlab.pipeline.surface(tube, color=(1, 0, 0))
mlab.show()
# ----------------------------------------------------------
return
Upvotes: 0
Reputation: 1046
Connecting arbitrary lines between points with one call of points3d is possible and extremely fast. Use following code from the protein example
import mayavi.mlab as mlab
import numpy as np
connections = ((0,2),(3,5)) # point 0 and 2 and 3 and 5 are connected
x = np.random.randn(10)
y = np.random.randn(10)
z = np.random.randn(10)
pts = mlab.points3d(x, y, z)
pts.mlab_source.dataset.lines = np.array(connections)
tube = mlab.pipeline.tube(pts, tube_radius=0.15)
tube.filter.radius_factor = 1.
mlab.pipeline.surface(tube, color=(0.8, 0.8, 0))
mlab.show()
Upvotes: 4