16

ズーム中にすべての「スレーブ」プロットの y 軸を自動スケーリングする、リンクされた (共有された) x 軸を持つプロットのスタックを作成するにはどうすればよいですか? 例えば:

import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212, sharex=ax1)
ax1.plot([0,1])
ax2.plot([2,1])
plt.show()

ax1 を拡大すると、ax2 の x 軸も更新されますが (これまでのところは問題ありません)、現在表示されているデータ範囲に基づいて ax2 の y 軸も自動スケーリングする必要があります。すべての自動スケール設定がオンになっています (デフォルト)。ax2 の作成後に自動スケール設定を手動で設定しても役に立ちませんでした。

ax2.autoscale(enable=True, axis='y', tight=True)
ax2.autoscale_view(tight=True, scalex=False, scaley=True)

print ax2.get_autoscaley_on()
-> True

私は何か見落としてますか?

4

2 に答える 2

25

matplotlib の axes.py の詳細を調べたところ、データのビューに基づいて軸を自動スケーリングするための規定がないように見えるため、私が望んでいたことを達成するための高レベルの方法はありません。

ただし、コールバックをアタッチできる「xlim_changed」イベントがあります。

import numpy as np

def on_xlim_changed(ax):
    xlim = ax.get_xlim()
    for a in ax.figure.axes:
        # shortcuts: last avoids n**2 behavior when each axis fires event
        if a is ax or len(a.lines) == 0 or getattr(a, 'xlim', None) == xlim:
            continue

        ylim = np.inf, -np.inf
        for l in a.lines:
            x, y = l.get_data()
            # faster, but assumes that x is sorted
            start, stop = np.searchsorted(x, xlim)
            yc = y[max(start-1,0):(stop+1)]
            ylim = min(ylim[0], np.nanmin(yc)), max(ylim[1], np.nanmax(yc))

        # TODO: update limits from Patches, Texts, Collections, ...

        # x axis: emit=False avoids infinite loop
        a.set_xlim(xlim, emit=False)

        # y axis: set dataLim, make sure that autoscale in 'y' is on 
        corners = (xlim[0], ylim[0]), (xlim[1], ylim[1])
        a.dataLim.update_from_data_xy(corners, ignore=True, updatex=False)
        a.autoscale(enable=True, axis='y')
        # cache xlim to mark 'a' as treated
        a.xlim = xlim

for ax in fig.axes:
    ax.callbacks.connect('xlim_changed', on_xlim_changed)

残念ながら、これは非常に低レベルのハックであり、簡単に壊れてしまいます (Lines 以外のオブジェクト、反転軸、対数軸など)。

より高いレベルのメソッドは、set_xlim() と「xlim_changed」コールバック。

さらに、水平方向にトリミングされたオブジェクトの垂直方向の範囲を決定する統一された方法はないようです。そのため、axes.py で Lines、Patches、Collections などを処理する別のコードがあり、これらはすべてコールバックで複製する必要があります。 .

いずれにせよ、私のプロットには行しかなく、タイト = True レイアウトに満足しているので、上記のコードはうまくいきました。Axes.py を少し変更するだけで、この機能をより洗練されたものにできるようです。

編集:

より高いレベルの自動スケール機能に接続できないというのは間違っていました。x と y を適切に分離するには、特定のコマンド セットが必要です。y で高レベルの自動スケーリングを使用するようにコードを更新しました。これにより、大幅に堅牢になるはずです。特に、tight=False が機能するようになり (結局のところ、はるかに見栄えが良くなりました)、逆/対数軸は問題になりません。

残っている 1 つの問題は、特定の x 範囲にトリミングされた後、すべての種類のオブジェクトのデータ制限を決定することです。この機能は、レンダラーが必要になる場合があるため、実際には組み込みの matplotlib である必要があります (たとえば、上記のコードは、画面に 0 または 1 ポイントしか残らないほどズームインすると壊れます)。メソッド Axes.relim() は良い候補のようです。データが変更された場合、データ制限を再計算することになっていますが、現在は Lines と Patches のみを処理します。x または y でウィンドウを指定する Axes.relim() へのオプションの引数が存在する可能性があります。

于 2012-06-19T14:37:11.403 に答える