it-swarm.com.de

Gemeinsames xlabel / ylabel für Matplotlib-Subplots

Ich habe das folgende Grundstück:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

und jetzt möchte ich diesem Plot allgemeine Beschriftungen für die x-Achse und die y-Achse geben. Mit "common" meine ich, dass es eine große Beschriftung auf der x-Achse unter dem gesamten Raster der Unterzeichnungen und eine große Beschriftung auf der y-Achse rechts geben sollte. Ich kann dazu nichts in der Dokumentation für plt.subplots Finden, und meine Google-Nutzer schlagen vor, dass ich zunächst ein großes plt.subplot(111) machen muss - aber wie stelle ich dann meine 5 * ein? 2 Unterzeichnungen mit plt.subplots?

105
jolindbe

Das sieht so aus, wie du es eigentlich willst. Es gilt der gleiche Ansatz von diese Antwort für Ihren speziellen Fall:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(nrows=3, ncols=3, sharex=True, sharey=True, figsize=(6, 6))

fig.text(0.5, 0.04, 'common X', ha='center')
fig.text(0.04, 0.5, 'common Y', va='center', rotation='vertical')

Multiple plots with common axes label

164
divenex

Ohne sharex=True, sharey=True du erhältst:

enter image description here

Damit solltest du es schöner machen:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.Rand(32,32))

plt.tight_layout()

enter image description here

Wenn Sie jedoch zusätzliche Beschriftungen hinzufügen möchten, sollten Sie diese nur den Edge-Plots hinzufügen:

fig, axes2d = plt.subplots(nrows=3, ncols=3,
                           sharex=True, sharey=True,
                           figsize=(6,6))

for i, row in enumerate(axes2d):
    for j, cell in enumerate(row):
        cell.imshow(np.random.Rand(32,32))
        if i == len(axes2d) - 1:
            cell.set_xlabel("noise column: {0:d}".format(j + 1))
        if j == 0:
            cell.set_ylabel("noise row: {0:d}".format(i + 1))

plt.tight_layout()

enter image description here

Das Hinzufügen einer Beschriftung für jeden Plot würde ihn zerstören (möglicherweise gibt es eine Möglichkeit, wiederholte Beschriftungen automatisch zu erkennen, mir ist jedoch keine bekannt).

33
Piotr Migdal

Da ich es für relevant und elegant genug halte (es müssen keine Koordinaten angegeben werden, um Text zu platzieren), kopiere ich (mit einer leichten Anpassung) eine Antwort auf eine andere verwandte Frage .

import matplotlib.pyplot as plt
fig, axes = plt.subplots(5, 2, sharex=True, sharey=True, figsize=(6,15))
# add a big axis, hide frame
fig.add_subplot(111, frameon=False)
# hide tick and tick label of the big axis
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.xlabel("common X")
plt.ylabel("common Y")

Dies führt zu folgenden Ergebnissen (mit matplotlib Version 2.2.0):

5 rows and 2 columns subplots with common x and y axis labels

21
bli

Seit dem Befehl:

fig,ax = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

sie haben ein Tupel zurückgegeben, das aus der Abbildung und einer Liste der Achseninstanzen besteht. Es reicht bereits aus, etwas zu tun (beachten Sie, dass ich fig,ax in fig,axes geändert habe):

fig,axes = plt.subplots(5,2,sharex=True,sharey=True,figsize=fig_size)

for ax in axes:
    ax.set_xlabel('Common x-label')
    ax.set_ylabel('Common y-label')

Wenn Sie Details zu einem bestimmten Untergrund ändern möchten, können Sie über axes[i] Darauf zugreifen, wobei i über Ihre Untergründe iteriert.

Es kann auch sehr hilfreich sein, a

fig.tight_layout()

am Ende der Datei, vor der plt.show(), um überlappende Bezeichnungen zu vermeiden.

14
Marius

Beim Zeichnen eines Graphengitters stieß ich auf ein ähnliches Problem. Die Grafiken bestanden aus zwei Teilen (oben und unten). Das y-Label sollte über beiden Teilen zentriert sein.

Ich wollte keine Lösung verwenden, die von der Kenntnis der Position in der äußeren Figur abhängt (wie fig.text ()), also habe ich die y-Position der set_ylabel () -Funktion manipuliert. Es ist normalerweise 0,5, die Mitte des Diagramms, zu dem es hinzugefügt wird. Da der Abstand zwischen den Teilen (hspace) in meinem Code Null war, konnte ich die Mitte der beiden Teile relativ zum oberen Teil berechnen.

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

# Create outer and inner grid
outerGrid = gridspec.GridSpec(2, 3, width_ratios=[1,1,1], height_ratios=[1,1])
somePlot = gridspec.GridSpecFromSubplotSpec(2, 1,
               subplot_spec=outerGrid[3], height_ratios=[1,3], hspace = 0)

# Add two partial plots
partA = plt.subplot(somePlot[0])
partB = plt.subplot(somePlot[1])

# No x-ticks for the upper plot
plt.setp(partA.get_xticklabels(), visible=False)

# The center is (height(top)-height(bottom))/(2*height(top))
# Simplified to 0.5 - height(bottom)/(2*height(top))
mid = 0.5-somePlot.get_height_ratios()[1]/(2.*somePlot.get_height_ratios()[0])
# Place the y-label
partA.set_ylabel('shared label', y = mid)

plt.show()

Bild

Nachteile:

  • Der horizontale Abstand zum Plot basiert auf dem oberen Teil, die unteren Häkchen können sich in das Etikett hinein erstrecken.

  • Die Formel berücksichtigt keinen Abstand zwischen den Teilen.

  • Löst eine Ausnahme aus, wenn die Höhe des oberen Teils 0 ist.

Es gibt wahrscheinlich eine allgemeine Lösung, die das Auffüllen von Zahlen berücksichtigt.

2
CPe

Ich habe eine robustere Methode entdeckt:

Wenn Sie die bottom und top Wargs kennen, die in eine GridSpec Initialisierung eingegangen sind, oder die Kantenpositionen Ihrer Achsen in Figure Koordinaten, Sie können auch die ylabel-Position in Figure Koordinaten mit etwas ausgefallener "Transformations" -Magie angeben. Beispielsweise:

import matplotlib.transforms as mtransforms
bottom, top = .1, .9
f, a = plt.subplots(nrows=2, ncols=1, bottom=bottom, top=top)
avepos = (bottom+top)/2
a[0].yaxis.label.set_transform(mtransforms.blended_transform_factory(
       mtransforms.IdentityTransform(), f.transFigure # specify x, y transform
       )) # changed from default blend (IdentityTransform(), a[0].transAxes)
a[0].yaxis.label.set_position((0, avepos))
a[0].set_ylabel('Hello, world!')

... und Sie sollten sehen, dass die Beschriftung wird immer noch von links nach rechts angepasst um zu verhindern, dass sie sich mit Ticklabels überschneidet, genau wie normal - aber jetzt wird sie immer angepasst genau dazwischen die gewünschten Untergrundstücke.

Wenn Sie nicht einmal set_position, das ylabel wird standardmäßig angezeigt genau in der Mitte der Abbildung. Ich vermute, das liegt daran, dass matplotlib beim endgültigen Zeichnen der Beschriftung 0,5 für die y-Koordinate verwendet, ohne zu überprüfen, ob sich die zugrunde liegende Koordinatentransformation geändert hat.

2
Luke Davis

Es sieht besser aus, wenn Sie Platz für die allgemeinen Beschriftungen reservieren, indem Sie unsichtbare Beschriftungen für die Unterzeichnung in der unteren linken Ecke erstellen. Es ist auch gut, die Schriftgröße von rcParams einzugeben. Auf diese Weise ändern sich die gemeinsamen Beschriftungen mit Ihrer RC-Konfiguration und die Achsen werden so angepasst, dass Platz für die gemeinsamen Beschriftungen bleibt.

fig_size = [8, 6]
fig, ax = plt.subplots(5, 2, sharex=True, sharey=True, figsize=fig_size)
# Reserve space for axis labels
ax[-1, 0].set_xlabel('.', color=(0, 0, 0, 0))
ax[-1, 0].set_ylabel('.', color=(0, 0, 0, 0))
# Make common axis labels
fig.text(0.5, 0.04, 'common X', va='center', ha='center', fontsize=rcParams['axes.labelsize'])
fig.text(0.04, 0.5, 'common Y', va='center', ha='center', rotation='vertical', fontsize=rcParams['axes.labelsize'])

enter image description hereenter image description here

1
EL_DON