I am working on a 3D visualization, in which I would like to mark part of the space, thus drawing something like a semi-transparent cloud in a given color.
I was googling for recipes and here is what I came up with. I try to make this cloud in a shape of a cube that would be green and half-transparent.
from mayavi import mlab
import numpy as np
def plot_volume():
# space 10 x 10 x 10 voxels, all have value = 0
s = np.zeros((10, 10, 10))
# now 64 voxels inside have value = 1
s[3:7:1, 3:7:1, 3:7:1] = 1
# we cut one corner to see if it will be asymmetric
s[3,3,3] = 0
fig = mlab.figure()
# This I do according to http://docs.enthought.com/mayavi/mayavi/auto/mlab_pipeline_sources.html#mayavi.tools.pipeline.scalar_field
sf = mlab.pipeline.scalar_field(s)
vol = mlab.pipeline.volume(sf)
# If I understand well, I should have volume with scalar values now
# What remains is manipulating its colors and opacity
# I take the recipie from here: http://docs.enthought.com/mayavi/mayavi/auto/mlab_pipeline_other_functions.html#volume
from tvtk.util.ctf import ColorTransferFunction
ctf = ColorTransferFunction()
# all points with value = 1 should be green
ctf.add_rgb_point(1, 0, 1, 0)
vol._volume_property.set_color(ctf)
vol._ctf = ctf
vol.update_ctf = True
# opacity
from tvtk.util.ctf import PiecewiseFunction
otf = PiecewiseFunction()
# all points with value = 1 should be semi-transparent
otf.add_point(1, 0.5)
# all points with value = 0 should not be visible at all
otf.add_point(0, 0)
vol._otf = otf
vol._volume_property.set_scalar_opacity(otf)
mlab.savefig('volume_auto.png')
mlab.show()
Basically, I am modifying examples from these two links: how to create a volume from scalar field and howto color it.
Sadly, the result is far from my expectation. The automatically saved figure looks like this:
Thus, the green color is not rendered at all. If I display the same thing in an interactive window, rotate it a bit, then the color appears:
But it is still far from perfect, instead of a green cubic cloud with a cut corner, I see a black cube with a cut corner, surrounded by a green mist. EDIT: this part of the problem is solved, when the non-zero value used is 255 instead of 1.
I would love to know how to fix these two problems and also I am happy not to use the volume, if there is a better way to plot a cloud I want. I tried plotting it with a bunch of cubes, like 3D pixels, it works fine, but is super slow, as many cube objects are created and the effect is like a video game from the 80'. I use mayavi 4.8.0.
OK, to solve it, one needs to do two things:
mlab.options.offscreen = True
. Solves the first problem I described (now green will be visible without interactive intervention).Weirdly enough, when calling ctf.add_rgb_point(value, ...)
we still need to do value = 1, which I don't understand.