Ich fand einen relativ einfachen (aber etwas unkonventionellen) Weg, um meine Matplotlib-Figuren zu speichern. Es funktioniert so:
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()))
mit einer so save_plot
definierten Funktion (einfache Version zum Verständnis der Logik):
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'
oder eine solche Funktion definieren save_plot
(bessere Version mit Zip-Komprimierung, um leichtere Figurendateien zu erstellen):
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'
Hierfür wird ein libscript
eigenes Modul verwendet , das hauptsächlich auf Modulen inspect
und basiert ast
. Ich kann versuchen, es auf Github zu teilen, wenn Interesse geäußert wird (es würde zuerst eine Bereinigung erfordern und ich, um mit Github zu beginnen).
Die Idee hinter dieser save_plot
Funktion und diesem libscript
Modul besteht darin, die Python-Anweisungen abzurufen, mit denen die Figur erstellt wird (mithilfe des Moduls inspect
), sie zu analysieren (mithilfe des Moduls ast
), um alle Variablen, Funktionen und Module zu extrahieren, auf die sie sich verlassen, diese aus dem Ausführungskontext zu extrahieren und sie zu serialisieren als Python-Anweisungen (Code für Variablen ist wie t=[0.0,2.0,0.01]
... und Code für Module ist wieimport matplotlib.pyplot as plt
...) vor den Abbildungen. Die resultierenden Python-Anweisungen werden als Python-Skript gespeichert, dessen Ausführung die ursprüngliche Matplotlib-Figur neu erstellt.
Wie Sie sich vorstellen können, funktioniert dies gut für die meisten (wenn nicht alle) Matplotlib-Figuren.