1

I'm writing a simple function to plot 2D data. I want the colorbar label on the x-axis of the colorbar, vertically aligned with the xlabel of the plot. Here's a MWE:

from matplotlib import pyplot as plt


def plot2d(x, y, z, xlabel, ylabel, zlabel, ax=None, **pcm_kwargs):
    if ax is None:
        fig, ax = plt.subplots(constrained_layout=True)
    else:
        fig = ax.get_figure()
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)

    pcm_kwargs.setdefault("shading", "auto")
    mesh = ax.pcolormesh(x, y, z, **pcm_kwargs)

    cb = fig.colorbar(mesh, ax=ax)
    cb.ax.set_xlabel(zlabel)

    fig.align_xlabels()
    return fig, ax


if __name__ == '__main__':
    import numpy as np
    x = np.linspace(0, 10, 100)
    y = np.linspace(0, 10, 100)
    z = np.random.random((100, 100))
    plot2d(x, y, z, xlabel="xlabel", ylabel="ylabel", zlabel="zlabel")
    plt.show()

First problem is that constrained_layout=True causes fig.colorbar to create an Axes instead of an AxesSubplot, so fig.align_xlabels() throws an error. But even if I remove constrained_layout=True, the xlabel and zlabel aren't vertically aligned:

.

I also tried setting the label's y position directly:

fig.canvas.draw()
cb.ax.xaxis.label.set_y(ax.xaxis.label.get_position()[1])

but still no effect.

How can I vertically align the plot and colorbar xlabels (within a constrained_layout if possible)?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
wfsch
  • 11
  • 2
  • What do you want to achieve in the following settings? `cb.ax.set_xlabel(zlabel, rotation=90)` – r-beginners Sep 11 '21 at 07:08
  • If you want the x-axis labels to be vertical as well, try the following. `ax.set_xlabel(xlabel, rotation=90)` – r-beginners Sep 11 '21 at 08:05
  • I don't want the text to be sideways, I want the two labels to be aligned, i.e. at the same y position – wfsch Sep 11 '21 at 14:00
  • So this is how you want to do it. `cb.set_label(zlabel, loc='center')` – r-beginners Sep 11 '21 at 15:04
  • No, that puts the label on the y-axis of the colorbar. – wfsch Sep 11 '21 at 16:20
  • If you look at the image linked in the op, I simply want the text "zlabel" to be vertically aligned with the text "xlabel", without hardcoding a labelpadding (which will break depending on the users rcparams). – wfsch Sep 11 '21 at 16:22

1 Answers1

0

So I had a similar issue with tick labels here. I've adapted it slightly for this question and this seems to work regardless of the font sizes. I tested from 7-18 point fonts.

cb = fig.colorbar(mesh, ax=ax)
r = plt.gcf().canvas.get_renderer()
coord = ax.xaxis.get_tightbbox(r)

xcoord = ax.xaxis.label.get_window_extent(renderer = r)
inv = ax.transData.inverted()
xcoord = inv.transform(xcoord)
xcoorddisplay = ax.transData.transform(xcoord)

cb.ax.set_xlabel(zlabel, labelpad = (xcoorddisplay[1][1]-xcoorddisplay[0][1])+8)
cmay
  • 153
  • 6