Iโm plotting a sphere with Mesh3d and Iโd like the light source to rotate with the plot. Right now, the specular reflection stays roughly fixed when I rotate the plot. Iโm trying to simulate the Sun shining on a planet, so the Sun needs to rotate with the planet when I change the viewing angle. Is there a way to do this?
The light position remains invariant no matter how you are moving the sphere, by mouse (the camera_eye position is also invariant). You can change light position through animation. Because the lighting and lightposition setttings for Mesh3d are similar to those for Surface, I illustrate the lightposition rotation for a parameterized sphere, defined as an instance of go.Surface.
LE: After a few experiments with different initial light positions, I noticed that go.Surface.lightposition
, as well as go.Mesh3d.lightposition
, has a lot of issues. No matter how the initial lightposition['z']
is set to a zl value, with -1<zl <1, and keeping xl=yl=10000, the light trajectory is the same during zaxis-rotation. When xl=yl=zl, the light spot does not rotate. This seems to be related to the default camera.eye
position that has eye.x=eye.y=eye.z
. @archmoj could explain whatโs going on. Is lightposition
buggy or not?
import numpy as np
from numpy import pi, sin, cos
import plotly.graph_objects as go
#Rotation about zaxis:
def rotate_z(x, y, z, theta):
w = x+1j*y
rw = np.exp(1j*theta)*w
return np.real(rw), np.imag(rw), z
#Sphere parameterization:
lon = np.linspace(0, 2*pi, 200)
lat = np.linspace(-pi/2, pi/2)
llon, llat = np.meshgrid(lon, lat)
x = cos(llon)*cos(llat)
y = sin(llon)*cos(llat)
z = sin(llat)
# constant colorscale
brown = [[0, '#9f3632'],
[1, '#9f3632']]
#initial light position:
xl = 10000
yl = 10000
zl = 0.75
fig = go.Figure(go.Surface(x=x, y=y, z=z,
colorscale=brown,
showscale=False,
lighting=dict(ambient=0.5,
diffuse=1,
fresnel=2,
specular=0.5,
roughness=0.5),
lightposition=dict(x=xl,
y=yl,
z=zl)))
fig.update_layout(dict(title='Animating Light Position Rotation',
width=800,
height=800));
fig.update_scenes( xaxis_visible=False,
yaxis_visible=False,
zaxis_visible=False,
camera_eye=dict(z=zl));
#define animation frames
frames = []
theta = np.linspace(0, 2*pi, 36)
for t in theta:
new_xl, new_yl, new_zl = rotate_z(xl, yl, zl, -t)
frames.append(go.Frame(data=[go.Surface(lightposition=dict(x=new_xl,
y=new_yl,
z=new_zl))],
traces=[0]))
fig.update(frames=frames)
fig.update_layout(updatemenus=[dict(type='buttons',
y=0.75,
x=1.05,
active=0,
buttons=[dict(label='Play',
method='animate',
args=[None,
dict(frame=dict(duration=50,
redraw=True),
transition=dict(duration=0),
fromcurrent=True,
mode='immediate')])])])
```