最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Align yaxis label spanning two axes with yaxis labels of one axes in subplots - Stack Overflow

programmeradmin0浏览0评论

I have a plot with 3 subplots: the top plot is larger than the two subsequent plots. They all share the same x- and y-axis. However, the ylabel is rather long, so the ylabels of the two bottom plots overlap (see img below). Here is the code:

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


imgs = [
    np.random.randn(200, 200),
    np.random.randn(50, 70),
    np.random.randn(100, 100),
]

figsize = [4, 6]
ylabel = "Long label for radius (cm)"

fig = plt.figure(figsize=figsize, layout="constrained")

gs = fig.add_gridspec(3, 1, height_ratios=[2, 1, 1])

axes = [fig.add_subplot(gs[i]) for i in range(3)]

for i in range(len(axes)):
    ax = axes[i]
    
    ax.imshow(imgs[i], aspect="auto")
    ax.set_xlabel("time (min)")
    
# from here on come different trials
for ax in axes:
    ax.set_ylabel(ylabel) 
fig.align_ylabels(axes)  # needed because of different y-ticks (100 vs 50)

I want to have a ylabel that spans the bottom two plots. I tried several things, that all do not work properly.

My first attempt was

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel, loc="bottom")
    
fig.align_ylabels(axes)

which gives correct x alignment but wrong y position:

Then, I tried

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel, loc="bottom", va="center")
fig.align_ylabels(axes)

giving a result failing with both, x and y alignment.

The best try so far was

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel)

ax = axes[1]
new_trafo = blended_transform_factory(
    x_transform=ax.yaxis.label.get_transform(),
    y_transform=ax.transAxes,
)
axes[1].set_ylabel(ylabel, y=0.0, va="center")
fig.align_ylabels(axes)

with this result (okayish y alignment that could be solved, but wrong x alignment).

None of the approaches worked properly. But there must be a way, to tell matplotlib that the bottom ylabel should have exactly the same x position (in figure pixels) as the top one even after recalculating the ylabel positions for layout="constrained" and fig.align_ylabels(axes). How can I fix this "alignment problem"?

EDIT: I am looking for a way to automatically get this desired output, where the two ylabels are aligned (having the same x position).

EDIT2: I want a matplotlib based solution. I could save/export the first try to svg and edit that output for correct y position of the bottom ylabel. But I think there is a solution within matplotlib.

Disclaimer: Splitting the ylabels of the bottom two plots in two lines is no solution for me, as it creates space between the top ylabel and its left axes neighbor. For simplicity, I have left out the left axes neighbor of the original problem, as described with the image below.

axes[0].set_ylabel(ylabel) 
for ax in axes[1:]:
    ax.set_ylabel("Long label\nfor radius (cm)")
fig.align_ylabels(axes)

I have a plot with 3 subplots: the top plot is larger than the two subsequent plots. They all share the same x- and y-axis. However, the ylabel is rather long, so the ylabels of the two bottom plots overlap (see img below). Here is the code:

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


imgs = [
    np.random.randn(200, 200),
    np.random.randn(50, 70),
    np.random.randn(100, 100),
]

figsize = [4, 6]
ylabel = "Long label for radius (cm)"

fig = plt.figure(figsize=figsize, layout="constrained")

gs = fig.add_gridspec(3, 1, height_ratios=[2, 1, 1])

axes = [fig.add_subplot(gs[i]) for i in range(3)]

for i in range(len(axes)):
    ax = axes[i]
    
    ax.imshow(imgs[i], aspect="auto")
    ax.set_xlabel("time (min)")
    
# from here on come different trials
for ax in axes:
    ax.set_ylabel(ylabel) 
fig.align_ylabels(axes)  # needed because of different y-ticks (100 vs 50)

I want to have a ylabel that spans the bottom two plots. I tried several things, that all do not work properly.

My first attempt was

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel, loc="bottom")
    
fig.align_ylabels(axes)

which gives correct x alignment but wrong y position:

Then, I tried

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel, loc="bottom", va="center")
fig.align_ylabels(axes)

giving a result failing with both, x and y alignment.

The best try so far was

axes[0].set_ylabel(ylabel)
axes[1].set_ylabel(ylabel)

ax = axes[1]
new_trafo = blended_transform_factory(
    x_transform=ax.yaxis.label.get_transform(),
    y_transform=ax.transAxes,
)
axes[1].set_ylabel(ylabel, y=0.0, va="center")
fig.align_ylabels(axes)

with this result (okayish y alignment that could be solved, but wrong x alignment).

None of the approaches worked properly. But there must be a way, to tell matplotlib that the bottom ylabel should have exactly the same x position (in figure pixels) as the top one even after recalculating the ylabel positions for layout="constrained" and fig.align_ylabels(axes). How can I fix this "alignment problem"?

EDIT: I am looking for a way to automatically get this desired output, where the two ylabels are aligned (having the same x position).

EDIT2: I want a matplotlib based solution. I could save/export the first try to svg and edit that output for correct y position of the bottom ylabel. But I think there is a solution within matplotlib.

Disclaimer: Splitting the ylabels of the bottom two plots in two lines is no solution for me, as it creates space between the top ylabel and its left axes neighbor. For simplicity, I have left out the left axes neighbor of the original problem, as described with the image below.

axes[0].set_ylabel(ylabel) 
for ax in axes[1:]:
    ax.set_ylabel("Long label\nfor radius (cm)")
fig.align_ylabels(axes)

Share Improve this question edited Jan 30 at 11:33 Niklas Netter asked Jan 30 at 10:09 Niklas NetterNiklas Netter 5710 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 2

After your base code, I used these 2 instructions to get the desired display:

axes[2].set_ylabel("")
axes[1].set_ylabel(ylabel, y=-0.4)

Plt.subplots can be used to create multiple axes and set shared y-axes so that y-axis labels can be aligned across two axes in subplots. You can position the label on one axis by using ax.set_ylabel(), and you can adjust its placement by using ax.yaxis.set_label_position(). For consistency of alignment, ensure that both subplots have the same y-axis.

发布评论

评论列表(0)

  1. 暂无评论