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.
Using subplots() method, create a figure and a set of subplots. Plot [1, 2, 3, 4, 5] data points on the left Y-axis scales. Using twinx() method, create a twin of Axes with a shared X-axis but independent Y-axis, ax2. Plot [11, 12, 31, 41, 15] data points on the right Y-axis scale, with blue color.
It is considered useful to have dual x or y axes in a figure. Moreso, when plotting curves with different units together. Matplotlib supports this with the twinxand twiny functions. In the following example, the plot has dual y axes, one showing exp(x) and the other showing log(x) − import matplotlib.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With