Reputation: 91
Let's say we have some 3D complex valued function f(x,y,z). Using Plotly, I'm trying to plot isosurfaces of the magnitude |f(x,y,z)| of such function. So far, everything is OK and my code seems to do well, please find below a working example on atomic orbitals functions :
import chart_studio.plotly as py
import plotly.graph_objs as go
import scipy.special as scispe
import numpy as np
import math
a=5.29e-11 # Bohr radius (m)
def orbital(n,l,m,r,theta,phi): # Complex function I want to plot
L=scispe.genlaguerre(n-l-1,2*l+1) # Laguerre polynomial
radial= (2/(n*a))**(3/2) * np.sqrt(math.factorial(n-l-1)/(2*n*math.factorial(n+l))) * np.exp(-2*r/n) * (2*r/n)**l * L(2*r/n)
wavefunction = radial * scispe.sph_harm(m,l, phi, theta)
return wavefunction
#Quantum numbers
n=2
l=1
m=0
goodspan = (3 * n**2 - l * (l+1))/2 #Plot span adpated to the mean electron position
x, y, z = np.mgrid[-goodspan:goodspan:40j, -goodspan:goodspan:40j, -goodspan:goodspan:40j] #in units of a
r = np.sqrt(x**2 + y**2 + z**2) #Function has to be evaluated in spherical coordinates
theta = np.arccos(z/r)
phi = np.arctan(y/x)
AO=orbital(n,l,m,r,theta,phi)
magnitude = abs(AO) # Compute the magnitude of the function
phase = np.angle(AO) # Compute the phase of the function
isoprob = np.amax(magnitude)/2 # Set value the isosurface
fig = go.Figure(data=go.Isosurface(
x=x.flatten(),
y=y.flatten(),
z=z.flatten(),
value=magnitude.flatten(),
opacity=0.5,
isomin=isoprob,
isomax=isoprob,
surface_count=1,
caps=dict(x_show=True, y_show=True)
))
fig.show()
At this point, the color scale of the graph is attributed depending on the value of the magnitude |f(x,y,z)|, so that a single isosurface is always uniform in color.
Now, instead to have a color scale mapped on the magnitude |f(x,y,z)|, I would like it to be mapped on the value of the phase Ф(x,y,z) = arg(f(x,y,z)), so that the color of each point of a ploted isosurface tells us about the value of the field Ф(x,y,z) (which would be distributed on [-π,π] ideally) instead of |f(x,y,z)| in thsi point.
Basically, I would like to do this with Plotly instead of Mayavi if it's possible.
It seems to me that all of that has something to do with a special way to set the cmin
and cmax
parameters of the function Isosurface
, but I can't figure out how to do this.
Upvotes: 4
Views: 1076
Reputation: 382
Given @Jan Joswig's answer and the link they provided, the quick/compact way of doing it will be:
import plotly.graph_objects as go
from skimage import measure
import numpy as np
xyz_shape = vol.shape
verts, faces = measure.marching_cubes(vol, .5)[:2] # iso-surface at .5 level
x, y, z = verts.T
I, J, K = faces.T
fig = go.Figure(
data=[go.Mesh3d(
x=x,
y=y,
z=z,
color='lightpink',
opacity=0.50,
i=I,
j=J,
k=K, )])
fig.show()
Upvotes: 1
Reputation: 733
As @gnodab mentioned in his comment, plotly isosurfaces do not really support colouring the surfaces by a fifth dimension (at least there is no obvious way to do it). I am also not sure if it might be possible to extract the data describing the isosurface somehow to be re-plotted as a regular surface.
In this post, however, they describe how to generate an isosurface with skimage.measure.marching_cubes_lewiner
which is then plotted and coloured by a custom colorscale with plotly as 'mesh3d'
trace. This might be what you want. If I find the time, I'll give that a try and edit my answer later.
Upvotes: 1