0
votes

I am trying to create a figure with several subplots that have a common colorbar. The subplots have to have an equal aspect ratio and the colorbar has to have the same height as the subplots. However, I don't manage to get a narrow colorbar with the same height as the other subplots.

I am using this recipe to generate a colorbar with a range suitable for all subplots; hence this issue is not addressed in the MWE.

When using the axes divider recipe to attach the colorbar, the height of the subplot changes due to the aspect ratio.

Here's the MWE

from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable

import itertools as it
import numpy as np

mean = [0, 0]
cov = [[1, 0.5],
       [0.5, 4]]
n_samples = 10000
hrange = [[-5,5],[-5,5]]
bins = 20

# RANDOM DATA
Z_random = np.random.multivariate_normal(mean, cov, size=n_samples)
Z, xedges, yedges = np.histogram2d(Z_random[:,0], Z_random[:,1], bins=bins, range=hrange, normed=True)
X, Y = np.meshgrid(xedges, yedges)

# PLOT PCOLORMESHS
fig, axes = plt.subplots(2,3, subplot_kw=dict(aspect="equal"))
axes = dict(enumerate(fig.get_axes(),1))

for i,ax in axes.items():
    if i==6:
        break
    pcm = ax.pcolormesh(X,Y,Z)

# PLOT COLORBAR
divider = make_axes_locatable(axes[6])
cax = divider.append_axes("left", size="15%", pad=0.0)
fig.colorbar(pcm, cax=cax, label=r"Colorbar label")

MWE

I can plot the colorbar over the complete subplot, in which case the height is correct, but it's much to wide to be appealing.

Does anybody have a "robust" solution, i.e. without manually fiddling around with the dimension of the subplots holding the colorbar?

Thanks in advance!

EDIT: Increased width of colorbar to emphasize that it becomes smaller in height.

1
Can you add an example of what you want it to look like? I am not sure exactly what you want. Your current solution looks pretty good if you remove the spines and ticks.ak_slick
Sorry, for the ambiguities. The colorbar is smaller in height than the actual plots. Depending on the spaces between the subplots etc. this can become more pronounced. I'd like to have the same height for the plots and the colorbar. Thx!Denis
take a look at the following SO answergyx-hh
You can also have a look here: stackoverflow.com/questions/18195758/…Sheldore

1 Answers

0
votes

If the only aim is to get the height of the colorbar correctly aligned with its horizontal neighbor, the last solution from this answer would help.

If however you also want the colorbar to be left-aligned with the plot on top of it, the solution is probably more complicated.

You may use a callback to set the position of the colorbar explicitely as follows:

from matplotlib import pyplot as plt
from matplotlib.transforms import Bbox
import numpy as np

mean = [0, 0]
cov = [[1, 0.5],
       [0.5, 4]]
n_samples = 10000
hrange = [[-5,5],[-5,5]]
bins = 20

# RANDOM DATA
Z_random = np.random.multivariate_normal(mean, cov, size=n_samples)
Z, xedges, yedges = np.histogram2d(Z_random[:,0], Z_random[:,1], bins=bins, range=hrange, normed=True)
X, Y = np.meshgrid(xedges, yedges)

# PLOT PCOLORMESHS
fig, axes = plt.subplots(2,3, subplot_kw=dict(aspect="equal"))

for i,ax in enumerate(axes.flat):
    if i==5:
        break
    pcm = ax.pcolormesh(X,Y,Z)

# PLOT COLORBAR
cax = fig.add_axes([0.6,0.01,0.1,0.4])
fig.colorbar(pcm, cax=cax, label=r"Colorbar label")

def align_cbar(cax, hax, vax):
    hpos = hax.get_position()
    vpos = vax.get_position()
    bb = Bbox.from_extents(vpos.x0, hpos.y0, vpos.x0+vpos.width*.05,hpos.y1)
    if cax.get_position() != bb:
        cax.set_position(bb)
        fig.canvas.draw_idle()

align_cbar(cax, axes[1,1], axes[0,2])    
fig.canvas.mpl_connect("draw_event", lambda x: align_cbar(cax, axes[1,1], axes[0,2]))

plt.show()

enter image description here