I would like to plot an orthogonal projection like this one:
orthogonal projection
using matplotlib, possibly including the 3D subplot. All the subplots should share common axes.
fig = plt.figure()
ax = fig.add_subplot(221, title="XZ")
bx = fig.add_subplot(222, title="YZ", sharey=ax)
cx = fig.add_subplot(223, title="XY", sharex=ax, sharey=[something like bx.Xaxis])
dx = fig.add_subplot(224, title="XYZ", projection="3d", sharex=ax, sharey=bx, sharez=[something like bx.Yaxis]
I can't figure out how to "link" the x-axis of one plot with the y-axis of another. Is there a way to accomplish this?
3 Answers 3
Late to the party but...
You should be able to accomplish what you want by manually updating one subplot's axis data with the other subplots axis data.
Using the notation from your post, for example, you can match the ylim
values of cx
with the xlim
values of bx
using the get
and set
methods.
cx.set_ylim(bx.get_ylim())
Similarly, you can match tick labels and positions across subplots.
bx_xticks = bx.get_xticks()
bx_xticklabels = [label.get_text() for label in bx.get_xticklabels()]
cx.set_yticks(bx_xticks)
cx.set_yticklabels(bx_xticklabels)
You should be able to define any and all axis attributes and objects dynamically from an already instantiated subplot in this way.
Here is my approach to the problem, which is basically a condensed version of @elebards answer. I just add update limit methods to the axes class, so they get access to the set_xlim / set_ylim methods. Then I connect these functions to the callbacks of the axis I want to synchronize it. When these are called the event argument will be filled with
import types
import matplotlib.pyplot as plt
def sync_y_with_x(self, event):
self.set_xlim(event.get_ylim(), emit=False)
def sync_x_with_y(self, event):
self.set_ylim(event.get_xlim(), emit=False)
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax1.update_xlim = types.MethodType(sync_y_with_x, ax1)
ax2.update_ylim = types.MethodType(sync_x_with_y, ax2)
ax1.callbacks.connect("ylim_changed", ax2.update_ylim)
ax2.callbacks.connect("xlim_changed", ax1.update_xlim)
I solved1 the problem by exploiting event handlers.
Listening for "*lim_changed"
events and then properly get_*lim
and set*_lim
to synchronise the limits does the trick.
Note you also have to reverse the x-axis in the upper right plot YZ.
Here is a sample function to sync the x-axis with the y-axis:
def sync_x_with_y(self, axis):
# check whether the axes orientation is not coherent
if (axis.get_ylim()[0] > axis.get_ylim()[1]) != (self.get_xlim()[0] > self.get_xlim()[1]):
self.set_xlim(axis.get_ylim()[::-1], emit=False)
else:
self.set_xlim(axis.get_ylim(), emit=False)
I implemented a simple class Orthogonal Projection that make quite easy to make such kind of plots.
1 Starting from a hint that Benjamin Root gave me on matplotlib mailing list almost a year ago...sorry for not having posted the solution before
Explore related questions
See similar questions with these tags.