python - pyplot - Guardar figuras Matplotlib interactivas
set title matplotlib (6)
¿Hay alguna manera de guardar una figura Matplotlib tal que se pueda volver a abrir y se restaure la interacción típica? (Como el formato .fig en MATLAB?)
Me encuentro ejecutando los mismos guiones muchas veces para generar estas figuras interactivas. O estoy enviando a mis colegas varios archivos PNG estáticos para mostrar diferentes aspectos de un gráfico. Prefiero enviar el objeto figura y hacer que interactúen con él ellos mismos.
¿Por qué no simplemente enviar la secuencia de comandos de Python? Los archivos .fig de MATLAB requieren que el destinatario tenga MATLAB para mostrarlos, por lo que equivale a enviar una secuencia de comandos de Python que requiere que se muestre Matplotlib.
Alternativamente (descargo de responsabilidad: aún no lo he probado), podría intentar decapar la figura:
import pickle
output = open(''interactive figure.pickle'', ''wb'')
pickle.dump(gcf(), output)
output.close()
A partir de Matplotlib 1.2, ahora contamos con soporte experimental para pickle . Pruébalo y ve si funciona bien para tu caso. Si tiene algún problema, háganos saber en la lista de correo Matplotlib o abriendo un problema en github.com/matplotlib/matplotlib .
Acabo de descubrir cómo hacer esto. El "soporte de pepinillo experimental" mencionado por @pelson funciona bastante bien.
Prueba esto:
# Plot something
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.plot([1,2,3],[10,-10,30])
Después de su ajuste interactivo, guarde el objeto figura como un archivo binario:
import pickle
pickle.dump(fig, open(''FigureObject.fig.pickle'', ''wb'')) # This is for Python 3 - py2 may need `file` instead of `open`
Más tarde, abra la figura y los ajustes se deben guardar y la interactividad de la GUI debe estar presente:
import pickle
figx = pickle.load(open(''FigureObject.fig.pickle'', ''rb''))
figx.show() # Show the figure, edit it, etc.!
Incluso puedes extraer los datos de las tramas:
data = figx.axes[0].lines[0].get_data()
(Funciona para líneas, pcolor e imshow - pcolormesh funciona con algunos trucos para reconstruir los datos aplanados ).
Obtuve la excelente sugerencia de Saving Matplotlib Figures Using Pickle .
Buena pregunta. Aquí está el texto del doc. De pylab.save
:
pylab ya no proporciona una función de guardado, aunque la antigua función pylab todavía está disponible como matplotlib.mlab.save (aún puede referirse a ella en pylab como "mlab.save"). Sin embargo, para archivos de texto sin formato, recomendamos numpy.savetxt. Para guardar matrices numpy, recomendamos numpy.save y su numpy.load analógico, que están disponibles en pylab como np.save y np.load.
Descubrí una forma relativamente simple (aunque poco convencional) de guardar mis figuras matplotlib. Funciona así:
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()))
con la función save_plot
definida así (versión simple para entender la lógica):
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''
o definiendo la función save_plot
como esta (mejor versión usando compresión zip para producir archivos de figura más ligeros):
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''
Esto hace uso de un módulo libscript
propio, que se basa principalmente en los módulos inspect
y ast
. Puedo tratar de compartirlo en Github si se expresa interés (en primer lugar, se requeriría cierta limpieza y yo empezaría con Github).
La idea detrás de esta función save_plot
y del módulo libscript
es buscar las instrucciones de python que crean la figura (usando el módulo inspect
), analizarlas (utilizando el módulo ast
) para extraer todas las variables, funciones y módulos de los que depende, extraerlos de la ejecución contexto y serializarlos como instrucciones de python (el código para las variables será como t=[0.0,2.0,0.01]
... y el código para los módulos será como import matplotlib.pyplot as plt
...) import matplotlib.pyplot as plt
a las instrucciones de la figura. Las instrucciones de python resultantes se guardan como un script de python cuya ejecución volverá a generar la figura de matplotlib original.
Como se puede imaginar, esto funciona bien para la mayoría (si no todas) las figuras matplotlib.
Esta sería una gran característica, pero AFAIK no está implementado en Matplotlib y es probable que sea difícil de implementar debido a la forma en que se almacenan las figuras.
Sugeriría (a) separar el procesamiento de los datos de la generación de la figura (que guarda datos con un nombre único) y escribir una secuencia generadora de gráficos (cargando un archivo específico de los datos guardados) y editarlos como lo considere oportuno o (b ) guardar como formato PDF / SVG / PostScript y editar en un sofisticado editor de figuras como Adobe Illustrator (o Inkscape ).
EDIT post de otoño de 2012 : como se señala a continuación (aunque se menciona aquí ya que esta es la respuesta aceptada), Matplotlib desde la versión 1.2 le ha permitido recortar las cifras. Como indican las notas de la versión , es una característica experimental y no es compatible con guardar una figura en una versión de matplotlib y abrir en otra. También es generalmente inseguro restaurar un pickle de una fuente no confiable.
Para parcelas de intercambio / edición posterior (que requieren un procesamiento de datos importante primero y pueden necesitar ser modificadas meses después durante una revisión científica), aún así recomiendo que el flujo de trabajo de (1) tenga un script de procesamiento de datos antes de generar un diagrama guarda los datos procesados (que van en su trazado) en un archivo, y (2) tiene un script de generación de trazado separado (que ajusta según sea necesario) para recrear el trazado. De esta forma, para cada trama puede ejecutar rápidamente una secuencia de comandos y volver a generarla (y copiar rápidamente la configuración de la trama con los datos nuevos). Dicho esto, conservar una cifra podría ser conveniente para el análisis de datos a corto plazo / interactivo / exploratorio.