web-dev-qa-db-ja.com

matplotlib savefig()プロットはshow()とは異なります

show()を使用してXにグラフをプロットすると、グラフは非常にきれいに見えます。ただし、savefig()を使用して大量のグラフを生成し始めると、savefig()で生成されたグラフのフォント、ライン、ポリゴンはすべて、show()で生成されたグラフより小さく見えます。私の環境はUbuntuで、show()のバックエンドはQt4Aggです。 show()プロットとsavefig()プロットを一致させるにはどうすればよいですか?

48
leon

savefigは、保存されたFigureのDPIを指定します(.matplotlibrcで指定されていない場合、デフォルトは100です。 dpi KWARG TO savefig を参照してください)。元の図のDPIには含まれません。

DPIは、テキストの相対的なサイズや線上のストロークの幅などに影響します。見た目を同じにしたい場合は、fig.dpifig.savefigに渡します。

例えば。

import matplotlib.pyplot as plt

fig = plt.figure()
plt.plot(range(10))
fig.savefig('temp.png', dpi=fig.dpi)
56
Joe Kington

matplotlibプロットを異なるデバイスにレンダリングします(例えば、異なる関数を使用して、Quartzを介して画面上に表示し、pdfを介してto-fileに表示します(plotvs savefig)そのパラメーターはほぼ同じですが、それらのパラメーターのデフォルト値は両方の関数で同じではありません。

別の言い方をすれば、savefigデフォルトのパラメーターはとは異なりますデフォルトのdisplayパラメーターです。

matplotlib config fileで行うと、それらの位置合わせは簡単です。テンプレートファイルはソースパッケージに含まれており、matplotlibrc.templateという名前です。matplotlibのインストール時にテンプレートを作成しなかった場合、このテンプレートはmatplotlibソースから取得できます。 matplotlib Webサイト から。

このファイルを希望どおりにカスタマイズしたら、名前をmatplotlibrc(拡張子なし)に変更し、ディレクトリ.matplotlib(先頭の「。」に注意してください。 )ホームディレクトリにある必要があります。

図の保存の設定パラメータは、提供されたmatplotlibrc.templateの約行314から始まります(このセクションの前の最初の行は### SAVING FIGURESです)。

特に、これらを見たいと思うでしょう:

savefig.dpi       : 100         # figure dots per inch
savefig.facecolor : white       # figure facecolor when saving
savefig.edgecolor : white       # figure edgecolor when saving
savefig.extension : auto        # what extension to use for savefig('foo'), or 'auto'

これらの行の下には、フォントタイプとさまざまな画像形式固有のパラメータの設定があります。

これらの同じパラメーター表示用、つまり、PLT.show()matplotlibrc.templateline 277aから始まります(このセクションは行:###図):

figure.figsize   : 8, 6          
figure.dpi       : 80            
figure.facecolor : 0.75       
figure.edgecolor : white     

これら2つのパラメーターブロックの値を比較するとわかるように、同じFigure属性のデフォルト設定は、savefigdisplay(show)のdifferentです。

27
doug

古い質問ですが、どうやらGoogleはそれを気に入っているようですので、この問題に関するいくつかの調査の後、ここに答えを入れようと思いました。

図を最初から作成する場合、作成時にサイズオプションを指定できます。

import matplotlib.pyplot as plt

fig = plt.figure(figsize=(3, 6))

plt.plot(range(10)) #plot example
plt.show() #for control

fig.savefig('temp.png', dpi=fig.dpi)

figsize(width、height)は、プロットの絶対寸法を調整し、両方のプロットが同じように見えるようにするのに役立ちます。

別の答えで述べたように、dpiオプションは、テキストの相対的なサイズや線上のストロークの幅などに影響します。オプションdpi = fig.dpiを使用すると、これらの相対的なサイズは、show()savefig()の両方で同じです。

または、作成後に図のサイズを変更することができます。

fig.set_size_inches(3, 6, forward=True)

forwardサイズをその場で変更できます。

作成された画像の境界線が大きすぎる場合に問題がある場合は、次のいずれかで調整できます。

plt.tight_layout()
#or:
plt.tight_layout(pad=2)

または:

fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight')
#or:
fig.savefig('temp.png', dpi=fig.dpi, bbox_inches='tight', pad_inches=0.5)

最初のオプションはレイアウトと境界線を最小化するだけで、2番目のオプションは境界線を少し手動で調整できます。これらのヒントは、少なくともsavefig()show()の画像の問題を解決するのに役立ちました。

8
brium-brium

私はmatplotlibソースでこれを修正しましたが、かなり修正されていません。ただし、私のように、グラフがどのように見えるかについて非常に細心の注意を払っている場合は、それだけの価値があります。

問題はレンダリングバックエンドにあるようです。それらはそれぞれ、線幅、フォントサイズなどの正しい値を取得しますが、PDFまたはPNGとしてレンダリングした場合は、show()でレンダリングした場合よりもわずかに大きくなります。

PNG生成のソースに、matplotlib/backends/backend_agg.pyファイルに数行追加しました。使用するバックエンドごとに同様の変更を行うか、単一の場所でより巧妙な変更を行う方法を見つけることができます;)

Matplotlib/backends/backend_agg.pyファイルに追加しました:

    # The top of the file, added lines 42 - 44
42  # @warning: CHANGED FROM SOURCE to draw thinner lines
43  PATH_SCALAR = .8
44  FONT_SCALAR = .95

    # In the draw_markers method, added lines 90 - 91
89  def draw_markers(self, *kl, **kw):
90      # @warning: CHANGED FROM SOURCE to draw thinner lines
91      kl[0].set_linewidth(kl[0].get_linewidth()*PATH_SCALAR)
92      return self._renderer.draw_markers(*kl, **kw)

    # At the bottom of the draw_path method, added lines 131 - 132:
130 else:
131     # @warning: CHANGED FROM SOURCE to draw thinner lines
132     gc.set_linewidth(gc.get_linewidth()*PATH_SCALAR)
133     self._renderer.draw_path(gc, path, transform, rgbFace)

    # At the bottom of the _get_agg_font method, added line 242 and the *FONT_SCALAR
241     font.clear()
242     # @warning: CHANGED FROM SOURCE to draw thinner lines
243     size = prop.get_size_in_points()*FONT_SCALAR
244     font.set_size(size, self.dpi)

これは今のところ私のニーズに合っていますが、あなたがやっていることによっては、他の方法で同様の変更を実装したいかもしれません。または、それほど行を変更せずに同じことを行うより良い方法を見つけてください!

更新: Githubのmatplotlibプロジェクトに問題を投稿した後、問題の原因を突き止めることができました。matplotlibrcファイルのfigure.dpi設定を変更しました。その値がデフォルトと異なる場合、savefig dpiをFigure dpiと同じに設定しても、savefig()イメージは異なって表示されます。したがって、上記のようにソースを変更する代わりに、figure.dpi設定をデフォルトの80のままにして、show()からの画像のように見えるsavefig()で画像を生成することができました。

レオン、その設定も変更しましたか?

4
Karmel