保存交互式Matplotlib数字

有没有办法保存一个Matplotlib图,使其可以重新打开,并恢复典型的交互? (像MATLAB中的.fig格式?)

我发现自己多次运行相同的脚本来生成这些交互式数字。 或者,我正在向同事发送多个静态PNG文件以显示剧情的不同方面。 我宁愿发送graphics对象,让他们自己与它们交互。

这将是一个很棒的function,但是AFAIK并没有在Matplotlib中实现,而且由于数据的存储方式,可能很难实现。

我build议(a)单独处理生成graphics(用唯一名称保存数据)的数据,并编写一个graphics生成脚本(加载保存的数据的指定文件),然后按照你的要求进行编辑或(b )保存为PDF / SVG / PostScript格式,并在Adobe Illustrator (或Inkscape )等一些奇特的graphics编辑器中进行编辑。

从Matplotlib 1.2开始,我们现在有了实验性的酱菜支持。 给你一个去看看它是否适合你的情况。 如果您有任何问题,请通过Matplotlib邮件列表或在github.com/matplotlib/matplotlib上打开问题告诉我们 。

我刚刚发现如何做到这一点。 @pelson提到的“实验泡菜支持”运作良好。

尝试这个:

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

在交互式调整之后,将graphics对象保存为二进制文件:

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

之后,打开graphics,调整应该保存,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使用一些技巧来重build扁平的数据 。)

我从保存Matplotlib使用泡菜的数字得到了优秀的技巧。

为什么不直接发送Python脚本? MATLAB的.fig文件要求收件人有MATLAB来显示它们,所以这相当于发送一个需要Matplotlib显示的Python脚本。

另外(免责声明:我还没有尝试过),你可以尝试酸洗这个数字:

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

好问题。 这是来自pylab.save的doc文本:

pylab不再提供保存function,尽pipe旧的pylab函数仍然可以用matplotlib.mlab.save(你仍然可以在pylab中将其称为“mlab.save”)。 但是,对于纯文本文件,我们推荐使用numpy.savetxt。 为了保存numpy数组,我们推荐使用numpy.save和它的模拟numpy.load,它们可以在pylab中作为np.save和np.load使用。

我想出了一个相对简单的方法(但稍微非常规)来保存我的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压缩产生更轻的graphics文件):

 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 ,这主要依赖于模块inspectast 。 我可以尝试在Github上分享,如果感兴趣的话(首先需要一些清理工作,然后我开始使用Github)。

这个save_plot函数和libscript模块的思想是获取创buildgraphics的Python指令(使用模块inspect ),分析它们(使用模块ast )来提取所有依赖的variables,函数和模块,从执行中提取这些指令上下文并将它们序列化为python指令(variables的代码将类似于t=[0.0,2.0,0.01] …,模块的代码将像import matplotlib.pyplot as plt …)预先添加到graphics指令中。 得到的python指令保存为一个python脚本,其执行将重新构build原始的matplotlibgraphics。

正如你可以想象的,这对大多数(如果不是全部的话)matplotlib数字很好。