4

バーでプロットを作成しており、後でさらに処理するために、プロット上の絶対位置 (ピクセル単位) を見つけようとしています。これは、軸インスタンスに関するmatplotlibの変換情報から把握できるはずです。具体的にはax.transData、データ座標 (ボックスの位置がわかっている場所) から座標を表示するために使用しています。ここにいくつかのコードがあります:

import matplotlib.pyplot as plt

x = range(10)
y = range(1, 11)

fig = plt.figure()
ax = fig.add_subplot(111)
bars = ax.bar(x, y, width=.5, label="foo")
ax.monkey_rectangles = bars
ax.legend()

def get_useful_info(fig):
    for ax in fig.get_axes():
        for rect in ax.monkey_rectangles:
            corners = rect.get_bbox().corners()[::3]
            pos = ax.transData.transform(corners)
            left = pos[0,0]
            width = pos[1,0] - pos[0,0]
            bottom = pos[0,1]
            height = pos[1,1] - pos[0,1]
            yield left, width, bottom, height

fig.savefig('foo.png')
for l, w, b, h in get_useful_info(fig):
    print l, w, b, h

これにより、次のように出力されます。

80.0 24.8 48.0 38.4
129.6 24.8 48.0 76.8
179.2 24.8 48.0 115.2
228.8 24.8 48.0 153.6
278.4 24.8 48.0 192.0
328.0 24.8 48.0 230.4
377.6 24.8 48.0 268.8
427.2 24.8 48.0 307.2
476.8 24.8 48.0 345.6
526.4 24.8 48.0 384.0

したがって、matplotlib は、私のボックスの幅が 24.8 ユニット (ピクセルと仮定) であると考えています。ボックスの幅を実際に測定する場合を除いて、それで問題ありません。幅は 32 ピクセル程度になります。ここでの矛盾は何ですか?

4

2 に答える 2

3

いつものように、質問を投稿するときに啓示が発生します...ここでの問題は、単位がピクセルではなく、ドットであることです。Figure が初期化されると、デフォルトの 1 インチあたりのドット数が設定されます (現在の Figure の解像度を変更/問い合わせることができます) fig.set_dpi()fig.get_dpi()もちろん、物事はそれほど簡単ではありません。Figure を保存すると、特定のバックエンドの rc 設定に基づいて dpi が変更されます。デフォルトのバックエンドと png 出力を使用している場合、これは 100 dpi になります。ただし、ここで不変であることの 1 つは、図のサイズfig.get_size_inches()です。したがって、結果をスケーリングすると、物事はもう少し一貫して変化するように見えます...

def get_useful_info(fig):
    dpi = fig.get_dpi()
    pngdpi = 100
    scale_x = pngdpi / dpi
    scale_y = pngdpi / dpi
    for ax in fig.get_axes():
        for rect in ax.monkey_rectangles:
            corners = rect.get_bbox().corners()[::3]
            pos = ax.transData.transform(corners)
            left = pos[0,0] * scale_x
            width = (pos[1,0] - pos[0,0]) * scale_x
            bottom = pos[0,1] * scale_y
            height = (pos[1,1] - pos[0,1]) * scale_y
            yield left, width, bottom, height

しかし、これが完全な解決策ではないという気持ちは沈みがちです -- 結局のところ、私たちはまだドットで作業しています。png画像のドットがどのようにピクセルに変換されるのか完全にはわかりません...表示エンジン(私の特定の場合、Webブラウザー)が各ドットを単一のピクセルでレンダリングし、画像の報告されたサイズ。いくつかの実験だけがそれを整理すると思います...

于 2013-09-18T10:40:19.997 に答える
1

Webブラウザについて言及しているように、イメージマップを構築していると思いますか?

import matplotlib.pyplot as plt

x = range(10)
y = range(1, 11)

fig = plt.figure()
ax = fig.add_subplot(111)
bars = ax.bar(x, y, width=.5, label="foo")
ax.monkey_rectangles = bars
ax.legend()

def fig_fraction_info(fig):
    for ax in fig.get_axes():
        inv = fig.transFigure.inverted()
        # transformations are applied left to right
        my_trans = ax.transData + inv 
        for rect in ax.monkey_rectangles:
            corners = rect.get_bbox().corners()[::3]
            pos = my_trans.transform(corners)
            left = pos[0,0]
            width = pos[1,0] - pos[0,0]
            bottom = pos[0,1]
            height = pos[1,1] - pos[0,1]
            yield left, width, bottom, height

このようなものが欲しいと思います。このデータと png を次のレベルのコードにフィードすると、すべてがどこにあるかを正確に整理できます。

このような問題は、(私が思うに) matplotlib がフロントエンドからバックエンドを抽象化する方法の結果です。サイズをピクセル単位で考えても、ベクター出力の場合はあまり意味がありません。

別の方法:

dpi = 300
...
fig.set_dpi(dpi)
...
fig.savefig(..., dpi=dpi)
于 2013-09-18T17:13:59.847 に答える