Reputation: 39
I'm trying to create a volume plot in R that will show the smoothed density of points in 3D space. I'm using plotly to plot with scatter3D at the moment.
df = data.frame(a = sample(seq(.5,.8,.001),100),
b = sample(seq(0,.5,.001),100),
c = sample(seq(0,.3,.001),100),
value = sample(seq(0,1,.01),100))
plot_ly(df, x = ~a, y = ~b, z = ~c, type = 'scatter3d')
Setting type to 'mesh3d' works to connect these points as a surface in 3d space.
plot_ly(df, x = ~a, y = ~b, z = ~c, type = 'mesh3d')
However, trying to set the type to 'volume' gives me a blank plot each time.
plot_ly(df, x = ~a, y = ~b, z = ~c, value = ~value, type = 'volume',
isomin = 0, isomax = 1, opacity = 1)
The documentation is here: https://plotly.com/r/reference/volume/ and specifies:
Draws volume trace between iso-min and iso-max values with coordinates given by four 1-dimensional arrays containing the
value
,x
,y
andz
of every vertex of a uniform or non-uniform 3-D grid. Horizontal or vertical slices, caps as well as spaceframe between iso-min and iso-max values could also be drawn using this trace.
The python version of plotly provides an example: https://plotly.com/python/3d-volume-plots/ but I don't know where I'm missing the conversion to R. I've included the extra value dimension for volume plots, but it doesn't seem to do anything.
Upvotes: 2
Views: 1157
Reputation: 96
Unlike the documentation of plotly where it states you can use non-uniform grids with a volume, plotting 3d volumes with isomin
and isomax
is actually not possible. Having a single coordinate which is non-uniform invalidates the whole plot. I struggled with the same issue for ages, wondering why my plots keep ending up blank.
To demonstrate, first create a plot with a uniform grid. For example, use the Python example from the resource you linked: https://plotly.com/python/3d-volume-plots/. (It doesn't matter that it's the Python API, rendering the plots is language independent).
import plotly.graph_objects as go
import numpy as np
X, Y, Z = np.mgrid[-8:8:40j, -8:8:40j, -8:8:40j]
values = np.sin(X*Y*Z) / (X*Y*Z)
fig = go.Figure(data=go.Volume(
x=X.flatten(),
y=Y.flatten(),
z=Z.flatten(),
value=values.flatten(),
isomin=0.1,
isomax=0.8,
opacity=0.1, # needs to be small to see through all surfaces
surface_count=17, # needs to be a large number for good volume rendering
))
fig.show()
This should show a plot. Next, change the coordinate of one point:
X[0, 0, 0] += 1
And tada: it no longer works and shows an empty plot.
Upvotes: 1