How to share x axes of two subplots after they have been created
Question:
I’m trying to share two subplots axes, but I need to share the x axis after the figure was created. E.g. I create this figure:
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig = plt.figure()
ax1 = plt.subplot(211)
plt.plot(t,x)
ax2 = plt.subplot(212)
plt.plot(t,y)
# some code to share both x axes
plt.show()
Instead of the comment I want to insert some code to share both x axes.
How do I do this? There are some relevant sounding attributes
_shared_x_axes
and _shared_x_axes
when I check to figure axis (fig.get_axes()
) but I don’t know how to link them.
Answers:
The usual way to share axes is to create the shared properties at creation. Either
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1)
or
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
Sharing the axes after they have been created should therefore not be necessary.
However if for any reason, you need to share axes after they have been created (actually, using a different library which creates some subplots, like here might be a reason), there would still be a solution:
Using
ax1.get_shared_x_axes().join(ax1, ax2)
creates a link between the two axes, ax1
and ax2
. In contrast to the sharing at creation time, you will have to set the xticklabels off manually for one of the axes (in case that is wanted).
A complete example:
import numpy as np
import matplotlib.pyplot as plt
t= np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212)
ax1.plot(t,x)
ax2.plot(t,y)
ax1.get_shared_x_axes().join(ax1, ax2)
ax1.set_xticklabels([])
# ax2.autoscale() ## call autoscale if needed
plt.show()
The other answer has code for dealing with a list of axes:
axes[0].get_shared_x_axes().join(axes[0], *axes[1:])
Just to add to ImportanceOfBeingErnest’s answer above:
If you have an entire list
of axes objects, you can pass them all at once and have their axes shared by unpacking the list like so:
ax_list = [ax1, ax2, ... axn] #< your axes objects
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list)
The above will link all of them together. Of course, you can get creative and sub-set your list
to link only some of them.
Note:
In order to have all axes
linked together, you do have to include the first element of the axes_list
in the call, despite the fact that you are invoking .get_shared_x_axes()
on the first element to start with!
So doing this, which would certainly appear logical:
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list[1:])
… will result in linking all axes
objects together except the first one, which will remain entirely independent from the others.
As of Matplotlib v3.3 there now exist Axes.sharex
, Axes.sharey
methods:
ax1.sharex(ax2)
ax1.sharey(ax3)
Function join
has been deprecated and will be removed soon. Continuing with this function is not recommended.
You can use the method suggested by iacob
but, as commented by Trevor Boyd Smith, sharex
and sharey
can only be called once on the same object.
Thus the solution is to select one single axis as the argument of calls from multiple axes which need to be associated with the first one, e.g. to set the same y-scale for axes ax1
, ax2
and ax3
:
- Select
ax1
as the argument for other calls.
- Call
ax2.sharey(ax1)
, ax3.sharey(ax1)
, and so on if required.
Since the .get_shared_x_axes().join()
method is deprecated, here is a function using ax.sharex()
that also removes the tick labels of inner plots (as using sharex=True
at construction time does) and works across figures:
def share_axes(axes, sharex=True, sharey=True):
if isinstance(axes, np.ndarray):
axes = axes.flat # from plt.subplots
elif isinstance(axes, dict):
axes = list(axes.values()) # from plt.subplot_mosaic
else:
axes = list(axes)
ax0 = axes[0]
for ax in axes:
if sharex:
ax.sharex(ax0)
if not ax.get_subplotspec().is_last_row():
ax.tick_params(labelbottom=False)
if sharey:
ax.sharey(ax0)
if not ax.get_subplotspec().is_first_col():
ax.tick_params(labelleft=False)
Usage:
import matplotlib.pyplot as plt
import numpy as np
fig1, axes1 = plt.subplots(2, 2, figsize=(3, 3))
fig2, axes2 = plt.subplots(2, 2, figsize=(3, 3))
axes = [*axes1.flat, *axes2.flat]
for ax in axes:
ax.imshow(np.random.randint(0, 255, size=(10, 10, 3)))
share_axes(axes)
plt.show()
I’m trying to share two subplots axes, but I need to share the x axis after the figure was created. E.g. I create this figure:
import numpy as np
import matplotlib.pyplot as plt
t = np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig = plt.figure()
ax1 = plt.subplot(211)
plt.plot(t,x)
ax2 = plt.subplot(212)
plt.plot(t,y)
# some code to share both x axes
plt.show()
Instead of the comment I want to insert some code to share both x axes.
How do I do this? There are some relevant sounding attributes
_shared_x_axes
and _shared_x_axes
when I check to figure axis (fig.get_axes()
) but I don’t know how to link them.
The usual way to share axes is to create the shared properties at creation. Either
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212, sharex = ax1)
or
fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)
Sharing the axes after they have been created should therefore not be necessary.
However if for any reason, you need to share axes after they have been created (actually, using a different library which creates some subplots, like here might be a reason), there would still be a solution:
Using
ax1.get_shared_x_axes().join(ax1, ax2)
creates a link between the two axes, ax1
and ax2
. In contrast to the sharing at creation time, you will have to set the xticklabels off manually for one of the axes (in case that is wanted).
A complete example:
import numpy as np
import matplotlib.pyplot as plt
t= np.arange(1000)/100.
x = np.sin(2*np.pi*10*t)
y = np.cos(2*np.pi*10*t)
fig=plt.figure()
ax1 = plt.subplot(211)
ax2 = plt.subplot(212)
ax1.plot(t,x)
ax2.plot(t,y)
ax1.get_shared_x_axes().join(ax1, ax2)
ax1.set_xticklabels([])
# ax2.autoscale() ## call autoscale if needed
plt.show()
The other answer has code for dealing with a list of axes:
axes[0].get_shared_x_axes().join(axes[0], *axes[1:])
Just to add to ImportanceOfBeingErnest’s answer above:
If you have an entire list
of axes objects, you can pass them all at once and have their axes shared by unpacking the list like so:
ax_list = [ax1, ax2, ... axn] #< your axes objects
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list)
The above will link all of them together. Of course, you can get creative and sub-set your list
to link only some of them.
Note:
In order to have all axes
linked together, you do have to include the first element of the axes_list
in the call, despite the fact that you are invoking .get_shared_x_axes()
on the first element to start with!
So doing this, which would certainly appear logical:
ax_list[0].get_shared_x_axes().join(ax_list[0], *ax_list[1:])
… will result in linking all axes
objects together except the first one, which will remain entirely independent from the others.
As of Matplotlib v3.3 there now exist Axes.sharex
, Axes.sharey
methods:
ax1.sharex(ax2)
ax1.sharey(ax3)
Function join
has been deprecated and will be removed soon. Continuing with this function is not recommended.
You can use the method suggested by iacob
but, as commented by Trevor Boyd Smith, sharex
and sharey
can only be called once on the same object.
Thus the solution is to select one single axis as the argument of calls from multiple axes which need to be associated with the first one, e.g. to set the same y-scale for axes ax1
, ax2
and ax3
:
- Select
ax1
as the argument for other calls. - Call
ax2.sharey(ax1)
,ax3.sharey(ax1)
, and so on if required.
Since the .get_shared_x_axes().join()
method is deprecated, here is a function using ax.sharex()
that also removes the tick labels of inner plots (as using sharex=True
at construction time does) and works across figures:
def share_axes(axes, sharex=True, sharey=True):
if isinstance(axes, np.ndarray):
axes = axes.flat # from plt.subplots
elif isinstance(axes, dict):
axes = list(axes.values()) # from plt.subplot_mosaic
else:
axes = list(axes)
ax0 = axes[0]
for ax in axes:
if sharex:
ax.sharex(ax0)
if not ax.get_subplotspec().is_last_row():
ax.tick_params(labelbottom=False)
if sharey:
ax.sharey(ax0)
if not ax.get_subplotspec().is_first_col():
ax.tick_params(labelleft=False)
Usage:
import matplotlib.pyplot as plt
import numpy as np
fig1, axes1 = plt.subplots(2, 2, figsize=(3, 3))
fig2, axes2 = plt.subplots(2, 2, figsize=(3, 3))
axes = [*axes1.flat, *axes2.flat]
for ax in axes:
ax.imshow(np.random.randint(0, 255, size=(10, 10, 3)))
share_axes(axes)
plt.show()