import plotly.graph_objects as go
def get_frame_line1(t):
t = t if t <= 1 else 1
t = t if t >= 0 else 0
x = -np.sin(np.linspace(-np.pi,t*np.pi-np.pi,100))
y = 0*np.linspace(-np.pi,t*np.pi-np.pi,100)
z = np.cos(np.linspace(-np.pi,t*np.pi-np.pi,100))
return x, y, z
def get_frame_line2(t):
t = t if t <= 1 else 1
t = t if t >= 0 else 0
x = np.sin(np.linspace(-np.pi,t*np.pi-np.pi,100))
y = 0*np.linspace(-np.pi,t*np.pi-np.pi,100)
z = np.cos(np.linspace(-np.pi,t*np.pi-np.pi,100))
return x, y, z
def get_frame_surface1(t):
t = t if t <= 1 else 1
t = t if t >= 0 else 0
if t == 0:
x = 0*np.linspace(-1, 1, 100)
z = 0*np.linspace(-1, 1, 100)
x, z = np.meshgrid(x, z)
y = 0 * x
return x, y, z
# slice of a disk that slowly increases its angle
# kinda like a pizza slice
# top is (0,0,1), bottom is (0,0,0)
# grows along the surface spanned by (1,0,0) and (0,0,1)
# Define the radial and angular grids
theta = np.linspace(-t*np.pi*2 -np.pi/2, -np.pi/2, 100)
phi = np.linspace(0, np.pi / 2, 100)
theta, phi = np.meshgrid(theta, phi)
# Spherical to Cartesian coordinates conversion
x = np.sin(phi) * np.cos(theta)
y = np.cos(phi)
z = np.sin(phi) * np.sin(theta)
return x, y, z
def get_frame_surface2(t):
x,y,z = get_frame_surface1(t)
y = -y
return x,y,z
# Generate data for each frame
ts = np.linspace(0, 1, 100)
line_df = pd.DataFrame()
surface_df = pd.DataFrame()
for t in ts:
x1, y1, z1 = get_frame_line1(2*t)
x2, y2, z2 = get_frame_line2(2*t)
x3, y3, z3 = get_frame_surface1(4*(t-0.5))
x4, y4, z4 = get_frame_surface2(4*(t-0.75))
temp_line_df = pd.DataFrame({
'x1': x1, 'y1': y1, 'z1': z1,
'x2': x2, 'y2': y2, 'z2': z2,
't': t})
line_df = pd.concat([line_df, temp_line_df])
temp_surface_df = pd.DataFrame({
'x3': x3.flatten(), 'y3': y3.flatten(), 'z3': z3.flatten(),
'x4': x4.flatten(), 'y4': y4.flatten(), 'z4': z4.flatten(),
't': [t] * 10000}) # 10000 = 100x100
surface_df = pd.concat([surface_df, temp_surface_df])
frames = []
for t in ts:
line_row = line_df[line_df['t'] == t]
surface_row = surface_df[surface_df['t'] == t]
frames.append(go.Frame(
data=[
go.Scatter3d(x=line_row['x1'], y=line_row['y1'], z=line_row['z1'], mode='lines', line=dict(color='green', width=2)),
go.Scatter3d(x=line_row['x2'], y=line_row['y2'], z=line_row['z2'], mode='lines', line=dict(color='red', width=2)),
go.Surface(x=surface_row['x3'].values.reshape(100, 100), y=surface_row['y3'].values.reshape(100, 100), z=surface_row['z3'].values.reshape(100, 100), colorscale='reds', showscale=False),
go.Surface(x=surface_row['x4'].values.reshape(100, 100), y=surface_row['y4'].values.reshape(100, 100), z=surface_row['z4'].values.reshape(100, 100), colorscale='greens', showscale=False)
],
name=str(t)
))
# Create a figure using plotly.graph_objects
fig = go.Figure(
layout=go.Layout(
updatemenus=[dict(
type="buttons",
buttons=[dict(label="Play",
method="animate",
args=[None, {"frame": {"duration": 75, "redraw": True},
"fromcurrent": True}]),
dict(label="Pause",
method="animate",
args=[[None], {"frame": {"duration": 0, "redraw": False},
"mode": "immediate",
"transition": {"duration": 0}}])],
)],
sliders=[
dict(
active=0,
steps=[dict(method="animate",
args=[[f"{t}"], {"frame": {"duration": 75, "redraw": True},
"mode": "immediate",
"transition": {"duration": 0}}]) for t in ts]
)
]
),
frames=frames
)
# Add initial data
fig.add_trace(go.Scatter3d(
x=line_df['x1'].iloc[0:100], y=line_df['y1'].iloc[0:100], z=line_df['z1'].iloc[0:100],
mode='lines', line=dict(color='green', width=2)))
fig.add_trace(go.Scatter3d(
x=line_df['x2'].iloc[0:100], y=line_df['y2'].iloc[0:100], z=line_df['z2'].iloc[0:100],
mode='lines', line=dict(color='red', width=2)))
# surface plots
fig.add_trace(go.Surface(
x=surface_df['x3'].iloc[0:10000].values.reshape(100, 100),
y=surface_df['y3'].iloc[0:10000].values.reshape(100, 100),
z=surface_df['z3'].iloc[0:10000].values.reshape(100, 100),
colorscale='reds', showscale=False))
fig.add_trace(go.Surface(
x=surface_df['x4'].iloc[0:10000].values.reshape(100, 100),
y=surface_df['y4'].iloc[0:10000].values.reshape(100, 100),
z=surface_df['z4'].iloc[0:10000].values.reshape(100, 100),
colorscale='greens', showscale=False))
# Layout configuration
fig.update_layout(
scene=dict(
xaxis=dict(range=[-1, 1], autorange=False),
yaxis=dict(range=[-1, 1], autorange=False),
zaxis=dict(range=[-1, 1], autorange=False),
),
title_text="Attachment maps for the 1 and 2 cells",
)
# Show the figure
fig.show()