10

プロット領域を拡張して注釈を含める簡単な方法を知っている人はいますか? 一部のラベルが長い文字列や複数行の文字列である図があり、これらを軸にクリップするのではなく、軸を拡張して注釈を含めたいと考えています。

Autoscale_view はそれを行わず、 ax.relim は注釈の位置を取得しないため、オプションではないようです。

以下のコードのようなことを試みました。これは、すべての注釈をループして (それらがデータ座標にあると仮定します)、それらの範囲を取得し、それに応じて軸を更新しますが、理想的には、注釈をデータ座標に入れたくありません (それらは実際のデータポイントからオフセットされています)。

xmin, xmax = plt.xlim()
ymin, ymax = plt.ylim()
# expand figure to include labels
for l in my_labels:
    # get box surrounding text, in data coordinates
    bbox = l.get_window_extent(renderer=plt.gcf().canvas.get_renderer())
    l_xmin, l_ymin, l_xmax, l_ymax = bbox.extents
    xmin = min(xmin, l_xmin); xmax = max(xmax, l_xmax); ymin = min(ymin, l_ymin); ymax = max(ymax, l_ymax)
plt.xlim(xmin, xmax)
plt.ylim(ymin, ymax)
4

3 に答える 3

10

私もこれに苦労しました。重要な点は、実際にテキストを描画するまで、matplotlib がテキストの大きさを決定しないことです。したがって、明示的に を呼び出しplt.draw()て境界を調整し、再度描画する必要があります。

このメソッドは、ドキュメントget_window_extentに従って、データ座標ではなく、表示座標で回答を返すことになっています。ただし、キャンバスがまだ描画されていない場合は、 のキーワード引数で指定した座標系で応答するようです。そのため、上記のコードは を使用して動作しますが、 は動作しません。textcoordsannotatetextcoords='data''offset points'

次に例を示します。

x = np.linspace(0,360,101)
y = np.sin(np.radians(x))

line, = plt.plot(x, y)
label = plt.annotate('finish', (360,0),
                     xytext=(12, 0), textcoords='offset points',
                     ha='left', va='center')

bbox = label.get_window_extent(plt.gcf().canvas.get_renderer())
print(bbox.extents)

注釈を切り取ったプロット

array([ 12.     ,  -5.     ,  42.84375,   5.     ])

テキスト ラベルが軸内に収まるように範囲を変更します。指定された値はbboxあまり役に立ちません: ラベル付きのポイントに相対的なポイントであるため: x で 12 ポイントのオフセット、10 ポイントのフォント (-5 から 5 でイ)。そこから新しい一連の軸境界に到達する方法を理解することは自明ではありません。

ただし、メソッドを描画した後で再度メソッドを呼び出すと、まったく異なる bbox が得られます。

bbox = label.get_window_extent(plt.gcf().canvas.get_renderer())
print(bbox.extents)

今、私たちは得る

array([ 578.36666667,  216.66666667,  609.21041667,  226.66666667])

これは表示座標であり、慣れ親しんだ方法で変換できax.transDataます。したがって、ラベルを境界に入れるには、次のようにします。

x = np.linspace(0,360,101)
y = np.sin(np.radians(x))

line, = plt.plot(x, y)
label = plt.annotate('finish', (360,0),
                     xytext=(8, 0), textcoords='offset points',
                     ha='left', va='center')

plt.draw()
bbox = label.get_window_extent()

ax = plt.gca()
bbox_data = bbox.transformed(ax.transData.inverted())
ax.update_datalim(bbox_data.corners())
ax.autoscale_view()

固定プロット

プロットが一度描画された後は、plt.gcf().canvas.get_renderer()明示的に渡す必要がなくなったことに注意してください。get_window_extentまた、自動スケーリングが自動的にラウンド数までノッチできるように、update_datalim代わりにxlimand をylim直接使用しています。

この回答をノート形式でここに投稿しました。

于 2015-09-17T18:29:29.107 に答える
2

私にとってtight_layoutは通常問題を解決しましたが、場合によっては、次のようにsubplots_adjustで「手動」調整を使用する必要がありました。

fig = plt.figure()
fig.subplots_adjust(bottom=0.2, top=0.12, left=0.12, right=0.1)

通常、数値は劇的に変化しないため、実際のプロットから計算するのではなく、数値を修正できます。

ところで、例のように xlim を設定すると、プロットするデータの範囲のみが変更され、すべてのラベルの周りの白い領域は変更されません。

于 2012-07-24T14:26:17.287 に答える
1

ではmatplotlib1.1tight_layoutいくつかのレイアウトの問題を解決するために導入されました。ここに素敵なチュートリアルがあります。

于 2012-07-19T09:01:06.970 に答える