149 votes

Enregistrer des figures Matplotlib interactives

Y a-t-il un moyen de sauvegarder une figure Matplotlib de sorte qu'elle puisse être réouverte et que l'interaction typique soit restaurée? (Comme le format .fig dans MATLAB?)

Je me retrouve à exécuter les mêmes scripts plusieurs fois pour générer ces figures interactives. Ou bien j'envoie à mes collègues plusieurs fichiers PNG statiques pour montrer différents aspects d'un tracé. Je préférerais leur envoyer l'objet figure et qu'ils interagissent avec eux-mêmes.

0voto

Astrum42 Points 37

J'ai trouvé un moyen relativement simple (bien que légèrement non conventionnel) de sauvegarder mes figures matplotlib. Cela fonctionne comme suit :

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)

#
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('Aussi simple que possible, les gens')
plt.grid(True)
plt.show()
#

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

avec la fonction save_plot définie comme ceci (version simple pour comprendre la logique) :

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'

ou en définissant la fonction save_plot comme ceci (meilleure version utilisant la compression zip pour produire des fichiers de figure plus légers) :

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'

Cela utilise un module libscript que j'ai créé, qui repose principalement sur les modules inspect et ast. Je peux essayer de le partager sur Github si un intérêt est exprimé (cela nécessiterait d'abord un peu de nettoyage et que je m'initie à Github).

L'idée derrière cette fonction save_plot et le module libscript est de récupérer les instructions python qui créent la figure (en utilisant le module inspect), de les analyser (en utilisant le module ast) pour extraire toutes les variables, fonctions et modules importés dont elles dépendent, de les extraire du contexte d'exécution et de les sérialiser sous forme d'instructions python (le code des variables sera comme t=[0.0,2.0,0.01] ... et le code des modules sera comme import matplotlib.pyplot as plt ...) ajoutés aux instructions de la figure. Les instructions python résultantes sont sauvegardées sous forme d'un script python dont l'exécution reconstruira la figure matplotlib d'origine.

Comme vous pouvez l'imaginer, cela fonctionne bien pour la plupart (si ce n'est pour toutes) les figures matplotlib.

0voto

Sumit Points 11

Si vous cherchez à enregistrer des graphiques python sous forme de figure interactive à modifier et à partager avec d'autres personnes comme un fichier .fig MATLAB, vous pouvez essayer d'utiliser le code suivant. Ici, z_data.values est simplement un ndarray numpy et vous pouvez donc utiliser le même code pour tracer et enregistrer vos propres données. Pas besoin d'utiliser pandas alors.

Le fichier généré ici peut être ouvert et modifié de manière interactive par n'importe qui avec ou sans python en cliquant simplement dessus et en l'ouvrant dans des navigateurs comme Chrome/Firefox/Edge etc.

import plotly.graph_objects as go
import pandas as pd

z_data=pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv')

fig = go.Figure(data=[go.Surface(z=z_data.values)])

fig.update_layout(title='Élévation du mont Bruno', autosize=False,
                  width=500, height=500,
                  margin=dict(l=65, r=50, b=65, t=90))

fig.show()
fig.write_html("testfile.html")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X