Positioning the Colorbar

Positioning the colorbar

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

How to shift the colorbar position to right in matplotlib?

Use the pad attribute.

cbar = plt.colorbar(sc, shrink=0.9, pad = 0.05)

The documentation of make_axes() describes how to use pad: "pad: 0.05 if vertical, 0.15 if horizontal; fraction of original axes between colorbar and new image axes".

Relocate colorbar

You have to add additional axes (add_axes) to put your colorbar at the desired position:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d.axes3d import Axes3D, get_test_data
from matplotlib import cm
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

# set up a figure twice as wide as it is tall
fig = plt.figure(figsize=plt.figaspect(0.5))

#===============
# First subplot
#===============
# set up the axes for the first plot
ax = fig.add_subplot(1, 2, 1, projection='3d')

# plot a 3D surface like in the example mplot3d/surface3d_demo

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
ax.set_zlim(-1.01, 1.01)

# position of colorbar
# where arg is [left, bottom, width, height]
cax = fig.add_axes([0.15, .87, 0.35, 0.03])
fig.colorbar(surf, orientation='horizontal', cax=cax)
plt.show()

Sample Image

Matplotlib colorbar background and label placement

To your second question: you can use a negative labelpad value to move the label back towards the ticklabels, like this:

import numpy as np
import matplotlib.pyplot as plt

data = np.linspace(0, 10, num=256).reshape(16,16)

cf = plt.contourf(data, levels=(0, 2.5, 5, 7.5, 10))
cb = plt.colorbar(cf)

cb.set_ticklabels([r'$<10^{0}$', 1, 2, r'$10^{14}$', r'$10^{14}+12345678$'])
cb.set_label(r'$n_e$ in $m^{-3}$', labelpad=-40, y=0.45)

plt.show()

Using the parameter y, you can additionally move the label up or down for better symmetry.

The argument of labelpad is given in points (1/72 inch). y accepts values in [0, 1], 0.0 is the lower border and 1.0 the upper.

The result:

Script Output

Adjust matplotlib colorbar position

Two things:

  1. The yshift you use is rather small, so an effect my not be directly obvious.
  2. Calling plt.tight_layout() rearranges the axes, and thus overwrites the position you have set.

So you would probably want to first call plt.tight_layout() and afterwards change the position.

How to control colorbar position when using subplots in Matplotlib

The reason this happens is that plt.colorbar creates a new Axes object, which "steals" space from the lower Axes (this is the reason making a horizontal colourbar also affects the two original plots).

There are a few ways to work around this; one is to create a Figure with four Axes, allocate most of the space to the left ones, and just make one invisible:

import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as scignal
import random

array = np.random.random(10000)
t, f, Sxx = scignal.spectrogram(array,fs=100)

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(5, 6), gridspec_kw={'width_ratios': [19, 1]})
(ax1, blank), (ax2, ax_cb) = axes
blank.set_visible(False)
ax1.plot(array)
m = ax2.pcolormesh(Sxx)
fig.colorbar(m, cax=ax_cb)

Sample Image

Position colorbar inside figure

One may use a mpl_toolkits.axes_grid1.inset_locator.inset_axes to place an axes inside another axes. This axes can be used to host the colorbar. Its position is relative the the parent axes, similar to how legends are placed, using a loc argument (e.g. loc=3 means lower left). Its width and height can be specified in absolute numbers (inches) or relative to the parent axes (percentage).

cbaxes = inset_axes(ax1, width="30%", height="3%", loc=3) 

Sample Image

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

x = np.random.randn(60)
y = np.random.randn(60)
z = [np.random.random() for _ in range(60)]

fig = plt.figure()
gs = gridspec.GridSpec(1, 2)

ax0 = plt.subplot(gs[0, 0])
plt.scatter(x, y, s=20)

ax1 = plt.subplot(gs[0, 1])
cm = plt.cm.get_cmap('RdYlBu_r')
plt.scatter(x, y, s=20 ,c=z, cmap=cm)

fig.tight_layout()

cbaxes = inset_axes(ax1, width="30%", height="3%", loc=3)
plt.colorbar(cax=cbaxes, ticks=[0.,1], orientation='horizontal')

plt.show()

Note that in order to suppress the warning, one might simply call tight_layout prior to adding the inset axes.



Related Topics



Leave a reply



Submit