Mapping the color scale of 3D isosurface on a scalar field

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()

which gives me this:

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.

Теперь, вместо того чтобы отображать цветовую шкалу на величину | f (x, y, z)|, я бы хотел, чтобы она отображалась на значении фазы Ф (x, y, z) = arg (f (x, y, z)), так что цвет каждой точки нанесенной изоповерхности говорит нам о значении поля Ф (x, y, z) (которое будет распределено на [-Ï €, Ï €] в идеале) вместо | f (x, y, z)| в этой точке.

По сути, я хотел бы сделать это с помощью Plotly вместо Mayavi, если это возможно.

Мне кажется, что все это как-то связано с особым способом установки cmin а также cmax параметры функции Isosurface, но я не могу понять, как это сделать.

2 ответа

Учитывая ответ @Jan Joswig и предоставленную ими ссылку , быстрый / компактный способ сделать это будет:

      import plotly.graph_objects as go
from skimage import measure
import numpy as np
xyz_shape = vol.shape
x = np.linspace(0, xyz_shape[0] - 1, xyz_shape[0])
y = np.linspace(0, xyz_shape[1] - 1, xyz_shape[1])
z = np.linspace(0, xyz_shape[2] - 1, xyz_shape[2])
X, Y, Z = np.meshgrid(x, y, z)
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()

Как упомянул @gnodab в своем комментарии, сюжетные изоповерхности на самом деле не поддерживают окраску поверхностей пятым измерением (по крайней мере, нет очевидного способа сделать это). Я также не уверен, можно ли каким-то образом извлечь данные, описывающие изоповерхность, чтобы их можно было перенести на обычную поверхность.

Однако в этом посте они описывают, как сгенерировать изоповерхность с помощьюskimage.measure.marching_cubes_lewiner который затем отображается и раскрашивается пользовательской шкалой цветов с помощью plotly as 'mesh3d'след. Это может быть то, что вы хотите. Если я найду время, я попробую и отредактирую свой ответ позже.

Другие вопросы по тегам