26

傾きの異なる複数の対角線を含むプロットを作成します。これらの線に、線の傾きに一致するテキスト ラベルで注釈を付けたいと思います。

このようなもの:

注釈付きの行

これを行うための堅牢な方法はありますか?

textと の両方の回転パラメーターを試しましannotateたが、それらはデータ座標ではなく画面座標です (つまりx、xy 範囲に関係なく、常に画面上の度数です)。私の範囲xy範囲は桁違いに異なり、明らかに見かけの傾きは他の変数の中でも特にビューポートのサイズの影響を受けるため、固定度の回転ではうまくいきません。他のアイデアはありますか?

4

4 に答える 4

12

私は自分に合ったものを思いつきました。灰色の破線に注意してください。

注釈付きの行

回転は手動で設定する必要がありますが、これはdraw()レイアウト後に行う必要があります。したがって、私の解決策は、行を注釈に関連付けてから、それらを繰り返し処理してこれを行うことです:

  1. 行のデータ変換を取得します (つまり、データ座標から表示座標に移動します)
  2. 線に沿って 2 点を変換して座標を表示する
  3. 表示された直線の傾きを求める
  4. この勾配に一致するようにテキストの回転を設定します

回転されたテキストの matplotlib の処理がすべて間違っているため、これは完璧ではありません。テキストのベースラインではなく、境界ボックスによって整列されます。

テキストのレンダリングに興味がある場合のフォントの基本: http://docs.oracle.com/javase/tutorial/2d/text/fontconcepts.html

この例は、matplotlib の機能を示しています: http://matplotlib.org/examples/pylab_examples/text_rotation.html

行の横にラベルを適切に配置する唯一の方法は、垂直方向と水平方向の両方で中央に揃えることです。次に、ラベルが重ならないように左に 10 ポイントずらします。私のアプリケーションには十分です。

これが私のコードです。必要に応じて線を描画し、注釈を描画してから、ヘルパー関数でそれらをバインドします。

line, = fig.plot(xdata, ydata, '--', color=color)

# x,y appear on the midpoint of the line

t = fig.annotate("text", xy=(x, y), xytext=(-10, 0), textcoords='offset points', horizontalalignment='left', verticalalignment='bottom', color=color)
text_slope_match_line(t, x, y, line)

次に、レイアウトの後、前に別のヘルパー関数を呼び出します(インタラクティブな画像の場合、描画イベントに登録してハンドラーsavefigを呼び出す必要があると思います)update_text_slopes

plt.tight_layout()
update_text_slopes()

ヘルパー:

rotated_labels = []
def text_slope_match_line(text, x, y, line):
    global rotated_labels

    # find the slope
    xdata, ydata = line.get_data()

    x1 = xdata[0]
    x2 = xdata[-1]
    y1 = ydata[0]
    y2 = ydata[-1]

    rotated_labels.append({"text":text, "line":line, "p1":numpy.array((x1, y1)), "p2":numpy.array((x2, y2))})

def update_text_slopes():
    global rotated_labels

    for label in rotated_labels:
        # slope_degrees is in data coordinates, the text() and annotate() functions need it in screen coordinates
        text, line = label["text"], label["line"]
        p1, p2 = label["p1"], label["p2"]

        # get the line's data transform
        ax = line.get_axes()

        sp1 = ax.transData.transform_point(p1)
        sp2 = ax.transData.transform_point(p2)

        rise = (sp2[1] - sp1[1])
        run = (sp2[0] - sp1[0])

        slope_degrees = math.degrees(math.atan(rise/run))

        text.set_rotation(slope_degrees)
于 2013-09-14T09:19:34.297 に答える