Reputation: 2301
I'm trying to align multiple colorbars with subplots generated with either gridspec
or fig.add_subplots
. I'd like to add the colorbar with fig.add_axes
in matplotlib (v2.02), because it allows detailed alignment control. However, I need to get the figure position in order to do the alignment. The ax.get_position()
function does not appear to return the correct coordinates:
Here is an MWE:
import matplotlib.gridspec as gridspec
import scipy.misc
fig = plt.figure(1)
fig.set_tight_layout(True)
gs = gridspec.GridSpec(2,2)
ax = plt.subplot(gs[0,0])
lena = scipy.misc.face()
im = ax.imshow(lena)
axpos = ax.get_position() # bbox# get_position().get_points()
cbar_axis = fig.add_axes([axpos.x0, axpos.y0-0.1, axpos.width, 0.05])
colorbar = fig.colorbar(im, cax=cbar_axis, orientation="horizontal")
If I print axpos
after the code runs, and ax.get_position()
, the two are not the same. This suggests that ax.get_position()
is using stale information while the code is executing. I've tried adding plt.show()
and plt.draw()
and it does not fix this.
How can I get the axis position?
EDIT:
I've modified the solution posted below (https://stackoverflow.com/a/44731797/238882) to better show what I am trying to do and why make_axes_locatable
does not appear (yet) to work for me. I want two colorbars under one column, and one under another column. Doing this with make_axes_locatable
and the following code produces the figure below. I would like the figures to all remain equal sizes and aligned in a grid.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import scipy.misc
from mpl_toolkits.axes_grid1 import make_axes_locatable
plt.close(1)
fig, axes = plt.subplots(2,2)
fig.set_tight_layout(True)
lena = scipy.misc.face()
for i, ax in enumerate(axes.flatten()):
im = ax.imshow(lena)
divider = make_axes_locatable(ax)
if i == 2:
ax_cb = divider.new_vertical(size="10%", pad=0.3, pack_start=True)
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
ax_cb2 = divider.new_vertical(size="10%", pad=0.3, pack_start=True)
fig.add_axes(ax_cb2)
fig.colorbar(im, cax=ax_cb2, orientation="horizontal")
if i == 3:
ax_cb = divider.new_vertical(size="10%", pad=0.3, pack_start=True)
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
plt.show()
Upvotes: 2
Views: 2314
Reputation: 339230
Usually you don't want to use the absolute positions of the axes, because this might (as you found out) change depending on other artists drawn or the figure placed in a canvas.
If the aim is to position the colorbar below the axes, a useful way is to use mpl_toolkits.axes_grid1.make_axes_locatable
as seen in this official example.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import scipy.misc
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure(1)
fig.set_tight_layout(True)
gs = gridspec.GridSpec(2,2)
ax = plt.subplot(gs[0,0])
lena = scipy.misc.face()
im = ax.imshow(lena)
divider = make_axes_locatable(ax)
ax_cb = divider.new_vertical(size="5%", pad=0.3, pack_start=True)
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
plt.show()
Note that this is absolutely compatible with tight_layout
while setting an axes with add_axes
is not.
You may create further errorbars by dividing the axes further using a second call to divider.new_vertical
.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import scipy.misc
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, axes = plt.subplots(2,2)
fig.set_tight_layout(True)
lena = scipy.misc.face()
for i, ax in enumerate(axes.flatten()):
im = ax.imshow(lena)
divider = make_axes_locatable(ax)
ax_cb = divider.new_vertical(size="10%", pad=0.3, pack_start=True)
ax_cb2 = divider.new_vertical(size="10%", pad=0.3, pack_start=True)
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
if i % 2 - 1:
fig.add_axes(ax_cb2)
fig.colorbar(im, cax=ax_cb2, orientation="horizontal")
plt.show()
Edit for the edited part of the question:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import scipy.misc
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig, axes = plt.subplots(2,2)
fig.set_tight_layout(True)
lena = scipy.misc.face()
for i, ax in enumerate(axes.flatten()):
im = ax.imshow(lena)
divider = make_axes_locatable(ax)
ax_cb = divider.new_vertical(size="8%", pad=0.3, pack_start=True)
ax_cb2 = divider.new_vertical(size="8%", pad=0.02, pack_start=True)
if i == 2:
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
fig.add_axes(ax_cb2)
fig.colorbar(im, cax=ax_cb2, orientation="horizontal")
ax_cb.tick_params(bottom=False,labelbottom=False)
if i == 3:
fig.add_axes(ax_cb)
fig.colorbar(im, cax=ax_cb, orientation="horizontal")
plt.show()
Upvotes: 2