Positioning the colorbar
Asked Answered
C

3

86

I have a matplotlib plot with a colorbar attached. I want to position the colorbar so that it is horizontal, and underneath my plot.

I have almost done this via the following:

plt.colorbar(orientation="horizontal",fraction=0.07,anchor=(1.0,0.0))

But the colorbar is still overlapping with the plot slightly (and the labels of the x axis). I want to move the colorbar further down, but I can't figure out how to do it.

Credulity answered 9/11, 2012 at 15:9 Comment(0)
B
83

Edit: Updated for matplotlib version >= 3.

Three great ways to do this have already been shared in this answer.

The matplotlib documentation advises to use inset_locator. This would work as follows:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np

rng = np.random.default_rng(1)

fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(rng.random((11, 16)))
ax.set_xlabel("x label")

axins = inset_axes(ax,
                    width="100%",  
                    height="5%",
                    loc='lower center',
                    borderpad=-5
                   )
fig.colorbar(im, cax=axins, orientation="horizontal")

code output

Bratwurst answered 9/11, 2012 at 16:23 Comment(3)
please give a complete example which is runable.Uranie
I think rather than ax1.plot(your_data) you want img = ax1.imshow(your_data) then the last line is cb = plt.colorbar(img, cax=cbaxes).Rascally
I love this answer because it works just really nice in my examples. EXCEPT when I add a caption for the colobar. Then I can't see that. Can you help?Precision
T
127

using padding pad

In order to move the colorbar relative to the subplot, one may use the pad argument to fig.colorbar.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")

fig.colorbar(im, orientation="horizontal", pad=0.2)
plt.show()

enter image description here

using an axes divider

One can use an instance of make_axes_locatable to divide the axes and create a new axes which is perfectly aligned to the image plot. Again, the pad argument would allow to set the space between the two axes.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np; np.random.seed(1)

fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")

divider = make_axes_locatable(ax)
cax = divider.new_vertical(size="5%", pad=0.7, pack_start=True)
fig.add_axes(cax)
fig.colorbar(im, cax=cax, orientation="horizontal")

plt.show()

enter image description here

using subplots

One can directly create two rows of subplots, one for the image and one for the colorbar. Then, setting the height_ratios as gridspec_kw={"height_ratios":[1, 0.05]} in the figure creation, makes one of the subplots much smaller in height than the other and this small subplot can host the colorbar.

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

fig, (ax, cax) = plt.subplots(nrows=2,figsize=(4,4), 
                  gridspec_kw={"height_ratios":[1, 0.05]})
im = ax.imshow(np.random.rand(11,16))
ax.set_xlabel("x label")

fig.colorbar(im, cax=cax, orientation="horizontal")

plt.show()

enter image description here

Taeniacide answered 15/4, 2017 at 10:48 Comment(9)
How can I use your second example to place the colorbar on top of the image? I tried setting cax = divider.append_axes("top", size="5%", pad=.15), but then the tick marks overlaps the image. I've been trying to place it outwards following this answer without any success, as it was written using very unorthodox matplotlib objects that I'm unable to reproduce in your example.Proliferous
The last solution (with subplot) makes the shrink parameter useless and without effect. Any idea why?Canonist
@T.Boutelier Yes, that's expected. shrink does not apply to externally created axes.Taeniacide
Ok, thanks for the answer! So how is it possible to control the size of the colorbar with this solution (subplot)?Canonist
By creating a 2x3 grid (instead of 2x1), let the image fill all 3 columns, but the colorbar only the middle one.Taeniacide
How do you let the image filling the 3 columns? Doing ax[0,:].imshow() generates an error. Isn't it necessary to rely on GridSpec in that case?Canonist
Correct. You'd use a GridSpec.Taeniacide
@Taeniacide is that an easy way to fully control the cbar such as moving it to the left or the right?Noelyn
@Taeniacide how would you apply gridspec to this example in the case of a color bar spanning multiple plots?Calaverite
B
83

Edit: Updated for matplotlib version >= 3.

Three great ways to do this have already been shared in this answer.

The matplotlib documentation advises to use inset_locator. This would work as follows:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
import numpy as np

rng = np.random.default_rng(1)

fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(rng.random((11, 16)))
ax.set_xlabel("x label")

axins = inset_axes(ax,
                    width="100%",  
                    height="5%",
                    loc='lower center',
                    borderpad=-5
                   )
fig.colorbar(im, cax=axins, orientation="horizontal")

code output

Bratwurst answered 9/11, 2012 at 16:23 Comment(3)
please give a complete example which is runable.Uranie
I think rather than ax1.plot(your_data) you want img = ax1.imshow(your_data) then the last line is cb = plt.colorbar(img, cax=cbaxes).Rascally
I love this answer because it works just really nice in my examples. EXCEPT when I add a caption for the colobar. Then I can't see that. Can you help?Precision
V
1

This has gotten a lot easier with matplotlib version 3.7, where you now can simply use the location='bottom' keyword.

From the docs:

location : None or {'left', 'right', 'top', 'bottom'}
    The location, relative to the parent axes, where the colorbar axes
    is created.  It also determines the *orientation* of the colorbar
    (colorbars on the left and right are vertical, colorbars at the top
    and bottom are horizontal).  If None, the location will come from the
    *orientation* if it is set (vertical colorbars on the right, horizontal
    ones at the bottom), or default to 'right' if *orientation* is unset.

Example:

import matplotlib.pyplot as plt
import numpy as np

rng = np.random.default_rng(1)

fig, ax = plt.subplots(figsize=(4,4))
im = ax.imshow(rng.random((11, 16)))
ax.set_xlabel("x label")
fig.colorbar(im, location='bottom')

enter image description here

Veronique answered 4/10, 2023 at 4:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.