I'm looking for a volume visualization like Plotly's Volume
. I've tried most methods here, also tried vol3d.
How can I get closer to Plotly's visual? I'm simply looking to have a mostly fully transparent 3D plot, where (as I understand) values are locally grouped and represented as a colored "cloud" - and be able to use 2D colormaps (e.g. turbo). It doesn't have to be strictly accurate (e.g. antialiased).
Closest results below - describing:
isosurface
& isocaps
: colors are mapped incorrectly, max appears as min. The interior is also a bit too hollow (/ transparent).slice
: for colors to make sense, alpha
must be too low. Higher alpha
clutters everything with low values. alpha('color')
isn't transparent enough on inner values.vol3d
: lack of transparency, and looks brickish.Flipping sign and shifting input to isosurface
/ isocaps
makes difference that I don't understand, and I can't make sense of docs' definition of the isovalue
argument.
OPTS = {'iso', 'slice', 'vol3d', 'slice-color'};
OPT = OPTS{1};
[X, Y, Z] = ndgrid(linspace(-8,8,40), linspace(-8,8,40), linspace(-8,8,40));
D = sin(X.*Y.*Z) ./ (X.*Y.*Z) * 100;
D = max(min(D, 100), 20); % clip to [20, 100]
figure
colormap('turbo')
% make cube
xdim = size(X, 1);
daspect([size(X,2)/xdim, 1, size(X,3)/xdim])
switch OPT
case {'iso', 'vol3d'}
view(3)
axis tight
camlight left
camlight
lighting gouraud
if strcmp(OPT, 'iso')
isosurface(D, 20)
isocaps(D, 20)
alpha(.5)
else
vol3d('CData', D);
end
case {'slice', 'slice-color'}
g = linspace(-8,8,40);
h = slice(g,g,g, D, g,g,g);
set(h,'EdgeColor','none',...
'FaceColor','interp',...
'FaceAlpha','interp');
if strcmp(OPT, 'slice')
alpha(.01)
else
alpha('color')
end
end
import numpy as np
import plotly.graph_objs as go
import plotly.io as pio
pio.renderers.default = 'browser'
X, Y, Z = np.mgrid[-8:8:40j, -8:8:40j, -8:8:40j]
V = np.sin(X*Y*Z) / (X*Y*Z) * 100
V = np.clip(V, 20, 100)
vkw = dict(showscale=False, colorscale='turbo', surface_count=50, opacity=.2)
fig = go.Figure(go.Volume(x=X.flatten(), y=Y.flatten(), z=Z.flatten(),
value=V.flatten(), **vkw))
fig.show()
isosurface
plots one surface. This surface is defined by where the volumetric data is equal to isovalue
. I think this is the largest cause of the discrepancy between MATLAB and python.
I suspect you would want to iterate over different values of isovalue
in order to plot multiple surfaces.
The closest I can get is this (thanks to Till's answer here):
if strcmp(OPT, 'iso')
for ii = linspace(20, 100, 50)
patch(isosurface(D, ii, D), 'FaceAlpha', (ii/400).^2, 'FaceColor', 'interp', 'LineStyle', 'none');
patch(isocaps(D, ii), 'FaceAlpha', (ii/400).^2, 'FaceColor', 'interp', 'LineStyle', 'none');
end
else ...
alpha
can also be a fixed value, but in this example the inner surfaces have higher alpha - you can try tuning the values differently, but that was the closest I could get to plotly.