Wymyśliłem stosunkowo prosty (ale nieco niekonwencjonalny) sposób zapisywania moich danych matplotlib. Działa to tak:
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()))
z funkcją save_plot
zdefiniowaną w ten sposób (prosta wersja do zrozumienia logiki):
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'
lub definiując save_plot
taką funkcję (lepsza wersja wykorzystująca kompresję zip do tworzenia lżejszych plików z figurami):
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'
To sprawia, że używam libscript
własnego modułu , który w większości opiera się na modułach inspect
i ast
. Mogę spróbować udostępnić to na Githubie, jeśli wyrażone zostanie zainteresowanie (najpierw wymagałoby to uporządkowania i rozpoczęcia korzystania z Github).
Ideą tej save_plot
funkcji i libscript
modułu jest pobranie instrukcji Pythona, które tworzą figurę (za pomocą modułu inspect
), przeanalizowanie ich (za pomocą modułu ast
) w celu wyodrębnienia wszystkich zmiennych, funkcji i modułów, na których opiera się, wyodrębnienie ich z kontekstu wykonania i ich serializacja jako instrukcje Pythona (kod dla zmiennych będzie podobny do t=[0.0,2.0,0.01]
... a kod modułów będzie podobny do import matplotlib.pyplot as plt
...) dołączone do instrukcji rysunku. Wynikowe instrukcje w języku Python są zapisywane jako skrypt w języku Python, którego wykonanie spowoduje odtworzenie oryginalnej figury matplotlib.
Jak możesz sobie wyobrazić, działa to dobrze w przypadku większości (jeśli nie wszystkich) figur matplotlib.