matplotlibサブプロットの一般的なxlabel / ylabel


142

私は次のプロットを持っています:

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

そして今、私はこのプロットに共通のx軸ラベルとy軸ラベルを与えたいと思います。「共通」とは、サブプロットのグリッド全体の下に1つの大きなx軸ラベルがあり、右側に1つの大きなy軸ラベルがあることを意味します。のドキュメントでこれについて何も見つけることができずplt.subplots、グーグルでplt.subplot(111)最初に大きくする必要があることを示唆していますが、5 * 2サブプロットをどのように使用するのplt.subplotsですか?


2
質問の更新と、以下の回答に残されたコメントにより、これはstackoverflow.com/questions/6963035/…の
2013

私の質問はplt.subplots()に関するものであり、リンクする質問はadd_subplotを使用しているため、回避したいadd_subplotに切り替えない限り、その方法は使用できません。私は可能性があなたのリンクでの代替ソリューションとして与えられているplt.textソリューションを使用しますが、それは最もエレガントなソリューションではありません。
jolindbe 2013

詳しく説明すると、私が理解している限り、plt.subplotsは既存の軸環境内で一連のサブプロットを生成できませんが、常に新しい図を作成します。正しい?
jolindbe 2013

最もエレガントな解決策はここで見つけることができます:stackoverflow.com/questions/6963035/...
Mr.H

あなたのリンクは、4年以上前にフックされたユーザーによって提供されました(あなたのコメントのほんの数コメント)。前に述べたように、その解決策はadd_subplotに関係し、plt.subplots()には関係しません。
jolindbe

回答:


206

これは実際に欲しいもののように見えます。それはあなたの特定のケースにこの答えの同じアプローチを適用します:

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')

共通のAxesラベルを持つ複数のプロット


4
x-labelのx座標の0.5は、ラベルを中央のサブプロットの中央に配置しないことに注意してください。yticklabelsを考慮に入れるには、それよりも少し大きくする必要があります。
dbliss

2
を使用しない方法については、この回答をご覧くださいplt.text。サブプロットを作成しますが、1つのビットプロットを追加して非表示にし、xとyにラベルを付けます。
James Owers、2017年

ありがとう、一般的に働きました。使用時の破損の解決策はありtight_layoutますか?
serv-inc

3
@ serv-incをwithにtight_layout置き換える0.04と動作する0ようです。
divenex

3
使用fig.textはお勧めできません。これは、次のようなことを台無しにしますplt.tight_layout()
平和

54

私はそれを十分に関連性がありエレガントであると考えているので(テキストを配置するために座標を指定する必要はありません)、別の関連する質問への回答を(少し調整して)コピーします。

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")

これにより、次の結果になります(matplotlibバージョン2.2.0)。

共通のx軸とy軸のラベルが付いた5行2列のサブプロット


4
単純さのため、これは受け入れられる答えになるはずです。非常に簡単です。まだmatplotlib v3.xに関連しています。
カイルスワンソン、

複数の図形オブジェクトでどのように使用できるか知りたいのですが?fig.xlabel( "foo")が機能しません。
Horror Vacui

参考:人々がStackOverflowで暗いテーマを使用するようになったため、ラベルをほとんど読み取ることができないため、白い背景でpngをエクスポートする方がよい
xyzzyqed

@xyzzyqed stackoverflowに「テーマ」などが存在することを知りませんでした。また、図をどのようにエクスポートしたかさえ覚えていません。エクスポート時に背景を制御するにはどうすればよいですか?
bli

2
このソリューションの唯一の問題は、constrained_layout=True重複したラベルが作成されるため、使用時に機能しないことです。この場合、サブプロットの境界を手動で調整する必要があります。
baccandr

35

sharex=True, sharey=Trueあなたがなければ:

ここに画像の説明を入力してください

それであなたはそれをより良くするべきです:

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()

ここに画像の説明を入力してください

ただし、ラベルを追加する場合は、エッジプロットにのみ追加する必要があります。

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()

ここに画像の説明を入力してください

各プロットにラベルを追加すると、ラベルが台無しになります(たぶん、繰り返されるラベルを自動的に検出する方法があるかもしれませんが、私はそれを知りません)。


これは、たとえば、プロットの数が不明な場合(たとえば、任意の数のサブプロットで機能する一般化プロット関数を持っている場合)、はるかに困難です。
naught101

15

コマンド以来:

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

あなたが使用したのは、FigureとAxesインスタンスのリストで構成されるタプルを返します。次のようなことで既に十分です(私がに変更fig,axしたことを覚えておいてくださいfig,axes)。

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')

特定のサブプロットの詳細を変更したい場合は、サブプロットを反復処理するaxes[i]場所からアクセスできますi

また、

fig.tight_layout()

plt.show()ラベルの重複を避けるために、ファイルの最後、の前。


5
上で少し不明瞭だったのは残念です。「共通」とは、すべてのプロットの下に単一のxラベル、プロットの左側に単一のyラベルを意味し、これを反映するように質問を更新しました。
jolindbe

2
@JohanLindberg:ここおよび上記のコメントに関して:確かplt.subplots()に、新しいFigureインスタンスを作成します。このコマンドを使いbig_ax = fig.add_subplot(111)続けたい場合は、既に図があり、別の軸を追加できるため、を簡単に追加できます。その後、big_axHookedからのリンクに表示される方法を操作できます。
マリウス

あなたの提案に感謝しますが、そうする場合は、plt.subplots()の後にbig_axを追加する必要があり、そのサブプロットを他のすべての上に配置します-透明にしたり、何らかの方法で背面に送ったりできますか?Hookedのリンクのようにすべての色をなしに設定しても、すべてのサブプロットをカバーする白いボックスのままです。
jolindbe 2013

2
@JohanLindberg、あなたは正しい、私はそれをチェックしていなかった。しかし、あなたは簡単に大きな軸の背景色を設定することができますnone実行して:big_ax.set_axis_bgcolor('none')あなたはまた、labelcolorをしなければならないnone(夢中でリンクされている例とは反対に):big_ax.tick_params(labelcolor='none', top='off', bottom='off', left='off', right='off')
マリウス

2
エラーが発生します:AttributeError: 'numpy.ndarray' object has no attribute 'set_xlabel'ステートメント内ax.set_xlabel('Common x-label')。分かりますか?
hengxin 2014

5

左下隅のサブプロットのラベルを非表示にして、共通ラベル用のスペースを予約すると、見栄えがよくなります。rcParamsからfontsizeを渡すのも良い方法です。このように、一般的なラベルはrc設定でサイズを変更し、軸も一般的なラベルのためのスペースを残すように調整されます。

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'])

ここに画像の説明を入力してください ここに画像の説明を入力してください


1
見えないラベルの素敵な使い方!ありがとう
colelemonz

3

グラフのグリッドをプロットしているときに、同様の問題に遭遇しました。グラフは2つの部分(上と下)で構成されていました。yラベルは両方の部分の中央に配置されることになっています。

(fig.text()のような)外側の図の位置を知ることに依存するソリューションを使用したくなかったので、set_ylabel()関数のy位置を操作しました。これは通常、追加されるプロットの中央の0.5です。コード内のパーツ(hspace)間のパディングがゼロだったので、2つのパーツの中間を上部と比較して計算できました。

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()

画像

欠点:

  • プロットまでの水平距離は上部に基づいており、下部の目盛りはラベルまで延びる場合があります。

  • 式では、パーツ間のスペースは考慮されません。

  • 上部の高さが0の場合、例外をスローします。

おそらく、数値間のパディングを考慮に入れる一般的な解決策があります。


ねえ、私はあなたの答えのとおりにこれを非常に行う方法を見つけましたが、これらの問題のいくつかを解決するかもしれません。stackoverflow.com/a/44020303/4970632(下記)を参照してください
Luke Davis

2

更新:

この機能は、最近pypiでリリースしたproplot matplotlibパッケージの一部になりました。デフォルトでは、図を作成すると、ラベルは軸間で「共有」されます。


元の答え:

私はより堅牢な方法を発見しました:

初期化に入ったbottomtopクワーグがわかっている場合GridSpec、またはFigure座標の軸のエッジの位置がわかっている場合は、奇妙Figureな「変換」魔法を使って座標のylabel位置を指定することもできます。例えば:

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!')

...ラベル、通常と同様に、目盛りラベルと重ならないように左右適切に調整されていますが、今は常に正確に調整されています。、希望するサブプロットています。

さらに、を使用しない場合でもset_position、デフォルトでylabelが表示されます図のちょうど半分のところに。これは、ラベルが最終的に描画されるときに、基になる座標変換が変更されたかどうかを確認せずmatplotliby-coordinateに0.5を使用するためだと思います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.