Les méthodes des autres réponses ne fonctionneront pas correctement lorsque les yticks sont grands. L'étiquette y sera soit superposée avec des graduations, soit coupée à gauche ou complètement invisible / à l'extérieur de la figure.
J'ai modifié la réponse de Hagne pour qu'elle fonctionne avec plus d'une colonne de sous-graphiques, à la fois pour xlabel et ylabel, et cela déplace le graphique pour garder le ylabel visible sur la figure.
def set_shared_ylabel(a, xlabel, ylabel, labelpad = 0.01, figleftpad=0.05):
"""Set a y label shared by multiple axes
Parameters
----------
a: list of axes
ylabel: string
labelpad: float
Sets the padding between ticklabels and axis label"""
f = a[0,0].get_figure()
f.canvas.draw()
top = a[0,0].get_position().y1
bottom = a[-1,-1].get_position().y0
x0 = 1
x1 = 1
for at_row in a:
at = at_row[0]
at.set_ylabel('')
bboxes, _ = at.yaxis.get_ticklabel_extents(f.canvas.renderer)
bboxes = bboxes.inverse_transformed(f.transFigure)
xt = bboxes.x0
if xt < x0:
x0 = xt
x1 = bboxes.x1
tick_label_left = x0
plt.subplots_adjust(left=(x1 - tick_label_left) + figleftpad)
a[-1,-1].set_ylabel(ylabel)
a[-1,-1].yaxis.set_label_coords(figleftpad-labelpad,(bottom + top)/2, transform=f.transFigure)
y0 = 1
for at in axes[-1]:
at.set_xlabel('')
bboxes, _ = at.xaxis.get_ticklabel_extents(fig.canvas.renderer)
bboxes = bboxes.inverse_transformed(fig.transFigure)
yt = bboxes.y0
if yt < y0:
y0 = yt
tick_label_bottom = y0
axes[-1, -1].set_xlabel(xlabel)
axes[-1, -1].xaxis.set_label_coords((left + right) / 2, tick_label_bottom - labelpad, transform=fig.transFigure)
Cela fonctionne pour l'exemple suivant, alors que la réponse de Hagne ne dessinera pas le ylabel (car il est en dehors du canevas) et le ylabel de KYC chevauche les étiquettes de graduation:
import matplotlib.pyplot as plt
import itertools
fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
for i, a in enumerate(itertools.chain(*axes)):
a.plot([0,4**i], [0,4**i])
a.set_title(i)
set_shared_ylabel(axes, 'common X', 'common Y')
plt.show()
Alternativement, si vous êtes d'accord avec l'axe incolore, j'ai modifié la solution de Julian Chen afin que ylabel ne chevauche pas les étiquettes de graduation.
Fondamentalement, nous devons juste définir les ylims de l'incolore afin qu'il corresponde aux plus grands ylims des sous-tracés afin que les étiquettes de graduation incolores définissent l'emplacement correct pour le ylabel.
Encore une fois, nous devons réduire l'intrigue pour éviter l'écrêtage. Ici, j'ai codé en dur le montant à réduire, mais vous pouvez jouer pour trouver un nombre qui vous convient ou le calculer comme dans la méthode ci-dessus.
import matplotlib.pyplot as plt
import itertools
fig, axes = plt.subplots(3, 4, sharey='row', sharex=True, squeeze=False)
fig.subplots_adjust(hspace=.5)
miny = maxy = 0
for i, a in enumerate(itertools.chain(*axes)):
a.plot([0,4**i], [0,4**i])
a.set_title(i)
miny = min(miny, a.get_ylim()[0])
maxy = max(maxy, a.get_ylim()[1])
ax_invis = fig.add_subplot(111, frameon=False)
ax_invis.set_ylim([miny, maxy])
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")
plt.subplots_adjust(left=0.15)
plt.show()