Search code examples
matplotlibcolorbar

matplotlib: shorten a colorbar by half when the colorbar is created using axes_grid1


I am trying to shorten a colorbar by half. Does anyone know how to do this? I tried cax.get_position() and then cax.set_position(), but this method did not work.

Besides, it seems that axes created by axes_grid1 has the same bbox positions as the original axes. Is this a bug?

PS. I have to use axes_grid1 to create colorbar axes, because I need to use tight_layout() afterwards, and tight_layout() only applies to axes created by axes_grid1 but not ones created by add_axes().

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np
plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
bbox1 = ax.get_position()
print(bbox1)
bbox1 = cax.get_position()
print(bbox1)
plt.colorbar(im, cax=cax)
plt.show()

enter image description here


Solution

  • The whole point of the axes_divider is to divide the axes to make space for a new axes. This ensures that all axes have the same surrounding box. And that is the box you see being printed.

    Some of the usual ways to create a colorbar, at a certain location in the figue are shown in this question. Here the problem seems to be to be able to call tight_layout. This is achievable with the following two options. (There might be others still.)

    A. using gridspec

    I'm not too sure about the exact requirements here, but it seems that using a normal grid layout would be more in the direction of what you need here.

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.gridspec as gridspec
    
    fig = plt.figure()
    gs = gridspec.GridSpec(2, 2, width_ratios=[95,5],)
    
    ax = fig.add_subplot(gs[:, 0])
    
    im = ax.imshow(np.arange(100).reshape((10,10)))
    
    cax = fig.add_subplot(gs[1, 1])
    fig.colorbar(im, cax=cax, ax=ax)
    plt.tight_layout()
    plt.show()
    

    enter image description here

    B. Using axes_grid1

    If you really need to use axes_grid1, it might become a little bit more complicated.

    import matplotlib.pyplot as plt
    import matplotlib.axes
    from mpl_toolkits.axes_grid1 import make_axes_locatable, Size
    import numpy as np
    
    fig, ax = plt.subplots()
    
    im = ax.imshow(np.arange(100).reshape((10,10)))
    
    divider = make_axes_locatable(ax)
    
    pad = 0.03
    pad_size = Size.Fraction(pad, Size.AxesY(ax))
    
    xsize = Size.Fraction(0.05, Size.AxesX(ax))
    ysize = Size.Fraction(0.5-pad/2., Size.AxesY(ax))
    
    divider.set_horizontal([Size.AxesX(ax), pad_size, xsize])
    divider.set_vertical([ysize, pad_size, ysize])
    
    ax.set_axes_locator(divider.new_locator(0, 0, ny1=-1))
    
    
    cax = matplotlib.axes.Axes(ax.get_figure(),
                     ax.get_position(original=True))
    locator = divider.new_locator(nx=2, ny=0)
    cax.set_axes_locator(locator)
    
    fig.add_axes(cax)
    
    fig.colorbar(im, cax=cax)
    
    plt.tight_layout()
    plt.show()
    

    enter image description here