Basically I have two 3d axes in one figure, one animated built through matplotlib.aninmation and one 3d line plot, side by side. I'd like to add functionality so that when you rotate one axis, the other follows it's rotation; so for example a function that sends the current viewing angle to the other axis like;
angle1 = getviewingangle(ax1)
ax2.view_init(angle1)
angle2 = getviewngangle(ax2)
ax1.view_init(angle2)
etc. This is for comparing the animated path of a particle with it's pre-plotted trajectory.
In order to synchronize the rotation between two subplots in mplot3d you can connect the motion_notify_event
to a function that reads the angles from rotated plot and applies it to the respective other plot.
Here is an example from the gallery with the described functionality added.
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
import matplotlib.pyplot as plt
import numpy as np
n_angles = 36
n_radii = 8
radii = np.linspace(0.125, 1.0, n_radii)
angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
x = np.append(0, (radii*np.cos(angles)).flatten())
y = np.append(0, (radii*np.sin(angles)).flatten())
z = np.sin(-x*y)
fig = plt.figure( figsize=(13,6))
fig.subplots_adjust(left=0, right=1, top=1, bottom=0, wspace=0)
ax = fig.add_subplot(1, 2, 1, projection='3d')
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
ax.plot_trisurf(x, y, z, cmap=cm.jet, linewidth=0.2)
ax2.plot_trisurf(x, y, z, cmap=cm.viridis, linewidth=0.5)
def on_move(event):
if event.inaxes == ax:
ax2.view_init(elev=ax.elev, azim=ax.azim)
elif event.inaxes == ax2:
ax.view_init(elev=ax2.elev, azim=ax2.azim)
else:
return
fig.canvas.draw_idle()
c1 = fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()
It may make sense to additionally synchronize the zooming utility as well. In this case one may use the following function
def on_move(event):
if event.inaxes == ax:
if ax.button_pressed in ax._rotate_btn:
ax2.view_init(elev=ax.elev, azim=ax.azim)
elif ax.button_pressed in ax._zoom_btn:
ax2.set_xlim3d(ax.get_xlim3d())
ax2.set_ylim3d(ax.get_ylim3d())
ax2.set_zlim3d(ax.get_zlim3d())
elif event.inaxes == ax2:
if ax2.button_pressed in ax2._rotate_btn:
ax.view_init(elev=ax2.elev, azim=ax2.azim)
elif ax2.button_pressed in ax2._zoom_btn:
ax.set_xlim3d(ax2.get_xlim3d())
ax.set_ylim3d(ax2.get_ylim3d())
ax.set_zlim3d(ax2.get_zlim3d())
else:
return
fig.canvas.draw_idle()