対話型Matplotlibフィギュアの保存


119

MatplotlibのFigureを再度開いて、通常の対話を復元できるように保存する方法はありますか?(MATLABの.fig形式と同様ですか?)

私は同じスクリプトを何度も実行して、これらのインタラクティブな図を生成しています。または、プロットのさまざまな側面を示すために、同僚に複数の静的PNGファイルを送信しています。むしろ、フィギュアオブジェクトを送信して、自分で操作してもらいたいのです。

回答:


30

これはすばらしい機能ですが、私の知る限り、Matplotlibには実装されておらず、数値の格納方法が原因で、実装が難しい場合があります。

(a)データの処理を図の生成(データを一意の名前で保存)とは別に処理し、図の生成スクリプトを作成(保存されたデータの指定されたファイルをロード)して、必要に応じて編集するか、または(b )PDF / SVG / PostScript形式で保存し、Adobe Illustrator(またはInkscape)などの豪華な図エディタで編集します。

2012年秋の編集後:他の人が下で指摘したように(これは受け入れられる回答であるため、ここで言及します)、バージョン1.2以降のMatplotlibでは数値をピクルすることができました。リリースノート状態、それは実験的な機能であり、他の1つのmatplotlibのバージョンおよび開口部の図を保存することはできません。また、信頼できないソースからピクルスを復元することは、一般的に安全ではありません。

プロットを共有/後で編集する場合(最初に重要なデータ処理が必要であり、数か月後に科学出版物の査読中に言う必要があるかもしれません)、私はまだ(1)のワークフローにプロットを生成する前にデータ処理スクリプトを用意することをお勧めします(プロットに入る)処理されたデータをファイルに保存し、(2)プロットを再作成するための(必要に応じて調整する)独立したプロット生成スクリプトを用意します。このように、プロットごとに、スクリプトをすばやく実行して再生成できます(そして、新しいデータでプロット設定をすばやくコピーできます)。とはいえ、図を酸洗いすることは、短期/インタラクティブ/探索的データ分析に便利かもしれません。


2
これは実装されていないので、多少驚いたのですが、処理されたデータを中間ファイルに保存し、それとプロット用のスクリプトを同僚に送信します。ありがとう。
Matt

2
実装が難しいのではないかと思うので、MATLABの動作が不十分です。私がそれを使用したとき、図はMATLABをクラッシュさせるために使用され、わずかに異なるバージョンでさえ、他の.figファイルを読み取ることができませんでした。
エイドリアン・ラトナパラ

6
pickleMPLフィギュアで動作するようになったので、これを実行すると、Matlabの「.fig」フィギュアファイルのように、適切に機能するように見えます。それを行う方法の例については、以下の私の答え(今のところ?)を参照してください。
Demis

@Demis:ptomatoが以下の彼の回答で指摘したように、それはその時点ですでに存在していました。
strpeter、

@strpeter- このコメントで指摘されているように、Matlabの数値は2010年にはピクリングできませんでした。試験的な機能は、2012年秋にリリースされたmatplotlib 1.2で追加されました。そこに記されているように、matplotlibのバージョン間で機能することを期待したり、信頼できないソースからのピクルスを開いたりしないでください。
ジンボブ博士、18年

63

私はこれを行う方法を見つけました。@pelsonが言及した「実験的なピクルスのサポート」は非常にうまく機能します。

これを試して:

# Plot something
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.plot([1,2,3],[10,-10,30])

インタラクティブな調整後、Figureオブジェクトをバイナリファイルとして保存します。

import pickle
pickle.dump(fig, open('FigureObject.fig.pickle', 'wb')) # This is for Python 3 - py2 may need `file` instead of `open`

後で、図を開くと微調整が保存され、GUIの対話性が表示されます。

import pickle
figx = pickle.load(open('FigureObject.fig.pickle', 'rb'))

figx.show() # Show the figure, edit it, etc.!

プロットからデータを抽出することもできます。

data = figx.axes[0].lines[0].get_data()

(これは、pcolorおよびimshowの行で機能します。pcolormeshは、いくつかのトリックを使用して、平坦化されたデータを再構築します。)

私はピクルスを使用してMatplotlibのフィギュアを保存することから素晴らしいヒントを得ました。


これはバージョンの変更などに対して堅牢ではなく、py2.xとpy3.xの間の相互互換性がないと思います。また、pickleドキュメントには、オブジェクトがピクルス化(保存)されたときと同じように環境をセットアップする必要があると記載されていると思いましたがimport matplotlib.pyplot as plt、ピクルル化解除(ロード)するときに必要がないことがわかりました-ピクルス化されたファイルにインポートステートメントを保存します。
Demis

5
開いているファイルを閉じることを検討してください:例with open('FigureObject.fig.pickle', 'rb') as file: figx = pickle.load(file)
strpeter '17年

1
「AttributeError: 'Figure' object has no attribute '_cachedRenderer」
user2673238

スクリプトを継続させたくない場合は、直後に終了する可能性が高いので、代わりにをfigx.show()呼び出す必要がありますplt.show()
maechler、

38

Matplotlib 1.2の時点で、実験的なピクルのサポートが追加されました。それを試してみて、それがあなたのケースにうまくいくかどうか見てください。問題がある場合は、Matplotlibメーリングリストまたはgithub.com/matplotlib/matplotlibで問題を開いてお知らせください


2
何らかの理由で、この便利な機能をFigureの[名前を付けて保存]自体に追加できます。おそらく.pklを追加しますか?
ダッシュ1995年

良い考え@dashesy。あなたがそれを実装したいのなら、私はそれをサポートしますか?
pelson 2014年

1
これはバックエンドのサブセットでのみ機能しますか?OSXで単純な図を漬けようとすると、が表示されますPicklingError: Can't pickle <type '_macosx.GraphicsContext'>: it's not found as _macosx.GraphicsContext
15年

上記PicklingErrorplt.show()、ピクルスを行う前に呼び出す場合にのみ発生します。だからちょうどplt.show()後に置きpickle.dump()ます。
salomonvh

MacOS 10.11上のpy3.5では、順序はfig.show()問題に見えません-おそらくそのバグは修正されました。show()問題なく前後に漬けることができます。
Demis

7

なぜPythonスクリプトを送信しないのですか?MATLABの.figファイルは、受信者がMATLABにそれらを表示するように要求するため、Matplotlibの表示を必要とするPythonスクリプトを送信するのとほぼ同じです。

代わりに(免責事項:私はまだこれを試していません)、図を酸洗いすることもできます:

import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()

3
残念ながら、matplotlibの数値はピクル可能ではないため、このアプローチは機能しません。舞台裏では、酸洗いをサポートしていないC拡張機能が多すぎます。ただし、スクリプトとデータを送信するだけで完全に同意します。MATLABが保存した.figのポイントを実際に確認したことがないので、それらを使用したことはありません。とにかく、誰かがスタンドアロンのコードとデータを送信することは、結局のところ、私の経験では、最も簡単です。それでも、matplotlibのFigureオブジェクトがピクル可能である場合、それは素晴らしいことです。
Joe Kington、

1
前処理されたデータでさえ多少大きく、プロット手順は複雑です。しかし、唯一の頼みの綱のように見えます。ありがとう。
Matt

1
フィギュアは明らかにピクル可能になりました-かなりうまくいきます!以下の例。
Demis

pickleの利点は、すべてのFigure /サブプロットの間隔/位置をプログラムで調整する必要がないことです。MPLプロットのGUIを使用して、Figureの見栄えを良くしたり、MyPlot.fig.pickleファイルを保存したりすることができます。後で必要に応じて、プロットの表示を調整することができます。これは、Matlabの.figファイルの優れた点でもあります。イチジクのサイズ/アスペクト比を変更する必要がある場合に特に役立ちます(プレゼンテーション/論文に挿入するため)。
Demis

1

良い質問。これは、次のドキュメントテキストですpylab.save

pylabは保存機能を提供しなくなりましたが、古いpylab関数は引き続きmatplotlib.mlab.saveとして使用できます(pylabでは「mlab.save」として引き続き参照できます)。ただし、プレーンテキストファイルの場合は、numpy.savetxtをお勧めします。numpy配列を保存するには、numpy.saveとそのアナログnumpy.loadをお勧めします。これらはpylabでnp.saveおよびnp.loadとして利用できます。


これにより、pylabオブジェクトのデータが保存されますが、Figureを再生成することはできません。
ジンボブ博士、2010

正しい。私はその答えが使用するための推奨ではなかったことを明確にすべきpylab.saveです。実際、ドキュメントのテキストから、それを使用すべきではないようです。
Steve Tjoa

3Dフィギュアを送信する外部メソッドはありますか?exeファイルへの可能性も、簡単なGUI ...
CromeX

0

私は、matplotlibの数値を保存する比較的単純な方法(まだ少し変わった方法)を見つけました。それはこのように動作します:

import libscript

import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2*np.pi*t)

#<plot>
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('About as simple as it gets, folks')
plt.grid(True)
plt.show()
#</plot>

save_plot(fileName='plot_01.py',obj=sys.argv[0],sel='plot',ctx=libscript.get_ctx(ctx_global=globals(),ctx_local=locals()))

save_plotこのように定義された関数(ロジックを理解するためのシンプルなバージョン):

def save_plot(fileName='',obj=None,sel='',ctx={}):
    """
    Save of matplolib plot to a stand alone python script containing all the data and configuration instructions to regenerate the interactive matplotlib figure.

    Parameters
    ----------
    fileName : [string] Path of the python script file to be created.
    obj : [object] Function or python object containing the lines of code to create and configure the plot to be saved.
    sel : [string] Name of the tag enclosing the lines of code to create and configure the plot to be saved.
    ctx : [dict] Dictionary containing the execution context. Values for variables not defined in the lines of code for the plot will be fetched from the context.

    Returns
    -------
    Return ``'done'`` once the plot has been saved to a python script file. This file contains all the input data and configuration to re-create the original interactive matplotlib figure.
    """
    import os
    import libscript

    N_indent=4

    src=libscript.get_src(obj=obj,sel=sel)
    src=libscript.prepend_ctx(src=src,ctx=ctx,debug=False)
    src='\n'.join([' '*N_indent+line for line in src.split('\n')])

    if(os.path.isfile(fileName)): os.remove(fileName)
    with open(fileName,'w') as f:
        f.write('import sys\n')
        f.write('sys.dont_write_bytecode=True\n')
        f.write('def main():\n')
        f.write(src+'\n')

        f.write('if(__name__=="__main__"):\n')
        f.write(' '*N_indent+'main()\n')

return 'done'

または、次のsave_plotような関数を定義します(zip圧縮を使用して軽量のFigureファイルを生成するより良いバージョン):

def save_plot(fileName='',obj=None,sel='',ctx={}):

    import os
    import json
    import zlib
    import base64
    import libscript

    N_indent=4
    level=9#0 to 9, default: 6
    src=libscript.get_src(obj=obj,sel=sel)
    obj=libscript.load_obj(src=src,ctx=ctx,debug=False)
    bin=base64.b64encode(zlib.compress(json.dumps(obj),level))

    if(os.path.isfile(fileName)): os.remove(fileName)
    with open(fileName,'w') as f:
        f.write('import sys\n')
        f.write('sys.dont_write_bytecode=True\n')
        f.write('def main():\n')
        f.write(' '*N_indent+'import base64\n')
        f.write(' '*N_indent+'import zlib\n')
        f.write(' '*N_indent+'import json\n')
        f.write(' '*N_indent+'import libscript\n')
        f.write(' '*N_indent+'bin="'+str(bin)+'"\n')
        f.write(' '*N_indent+'obj=json.loads(zlib.decompress(base64.b64decode(bin)))\n')
        f.write(' '*N_indent+'libscript.exec_obj(obj=obj,tempfile=False)\n')

        f.write('if(__name__=="__main__"):\n')
        f.write(' '*N_indent+'main()\n')

return 'done'

これはlibscript、自分のモジュールを使用します。これは主にモジュールinspectとに依存していますast。関心が表明されている場合は、Githubで共有してみることができます(最初にクリーンアップが必要で、Githubを使い始めるには私が必要です)。

このsave_plot関数とlibscriptモジュールの背後にある考え方は、図を作成するPython命令を取得し(moduleを使用inspect)、それらを分析(moduleを使用ast)して、それが依存するすべての変数、関数、およびモジュールを抽出し、実行コンテキストからこれらを抽出してシリアル化することですPythonの命令(変数のコードはt=[0.0,2.0,0.01]...であり、モジュールのコードはimport matplotlib.pyplot as plt...である)が図の命令の前に追加されているため。結果のpython命令は、実行によって元のmatplotlibフィギュアが再構築されるpythonスクリプトとして保存されます。

ご想像のとおり、これは(すべてではないにしても)ほとんどのmatplotlibの数値に適しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.