Zapisywanie interaktywnych figur Matplotlib

Czy istnieje sposób, aby zapisać figurę Matplotlib tak, że można ją ponownie otworzyć i przywrócić typowe interakcje? (Np.format fig w Matlabie?)

Często uruchamiam te same skrypty, aby wygenerować te interaktywne figury. Albo wysyłam moim kolegom wiele statycznych plików PNG, aby pokazać różne aspekty fabuły. Wolałbym wysłać obiekt postaci i pozwolić im wejść z nim w interakcję.

Author: Peter Mortensen, 2010-12-03

6 answers

to byłaby świetna funkcja, ale AFAIK nie jest zaimplementowany w Matplotlib i prawdopodobnie byłoby trudne do zaimplementowania samodzielnie ze względu na sposób, w jaki dane są przechowywane.

Sugerowałbym albo (a) oddzielenie przetwarzania danych od generowania rysunku (co zapisuje dane o unikalnej nazwie) i napisanie skryptu generującego rysunek (Ładowanie określonego pliku zapisanych danych) i edycję według własnego uznania lub (B) zapisanie jako PDF / SVG/PostScript formatowanie i edycja w niektórych fantazyjny edytor rysunków jak Adobe Illustrator (lub Inkscape).

EDIT post Fall 2012: Jak inni zauważyli poniżej (choć wspominają tutaj, ponieważ jest to akceptowana odpowiedź), Matplotlib od wersji 1.2 pozwalał na marynowanie figur. Jako że release notes stan, jest to funkcja eksperymentalna i nie obsługuje zapisywania rysunku w jednej wersji matplotlib i otwierania w innej. Jest również ogólnie niezabezpieczone, aby przywrócić ogórek z niezaufanego źródło.

Do udostępniania/późniejszej edycji wykresów (które wymagają najpierw znacznego przetwarzania danych i mogą wymagać poprawek miesięcy później, powiedzmy podczas recenzji naukowej), nadal zalecam przepływ pracy (1) mieć skrypt przetwarzania danych, który przed wygenerowaniem wykresu zapisuje przetworzone dane (które trafiają do twojego wykresu) do pliku, i (2) mieć oddzielny skrypt generowania wykresu (który dostosowujesz w razie potrzeby), aby odtworzyć Wykres. W ten sposób dla każdej działki można szybko uruchom skrypt i wygeneruj go ponownie (i szybko skopiuj Ustawienia wykresu z nowymi danymi). To powiedziawszy, wytrawianie figury może być wygodne dla krótkoterminowej / interaktywnej / eksploracyjnej analizy danych.

 33
Author: dr jimbob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-11 23:48:17

Właśnie się dowiedziałem, jak to zrobić. Wspomniany przez @ Pelsona "experimental pickle support" działa całkiem nieźle.

Spróbuj tego:

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

Po interaktywnym dostosowaniu Zapisz obiekt figure jako plik binarny:

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

Później, otwórz rysunek i poprawki powinny być zapisane i interaktywność GUI powinna być obecna:

import pickle
figx = pickle.load(open('FigureObject.fig.pickle', 'rb'))

figx.show() # Show the figure, edit it, etc.!

Możesz nawet wyodrębnić dane z Wykresów:

data = figx.axes[0].lines[0].get_data()

(działa dla linii, pcolor & imshow - pcolormesh działa z niektórymi Triki do rekonstrukcji spłaszczonych danych .)

Dostałem świetną wskazówkę od zapisywanie figur Matplotlib za pomocą ogórka.
 69
Author: Demis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:48

Od Matplotlib 1.2 mamy teraz eksperymentalne wsparcie pickle . Spróbuj i sprawdź, czy to działa dobrze w twojej sprawie. Jeśli masz jakieś problemy, daj nam znać na liście dyskusyjnej Matplotlib lub otwierając problem na github.com/matplotlib/matplotlib .

 39
Author: pelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-05 08:14:06

Dlaczego po prostu nie wysłać skryptu Pythona? Matlaba .pliki fig wymagają, aby odbiorca miał MATLAB, aby je wyświetlić, więc jest to równoznaczne z wysłaniem skryptu Pythona, który wymaga wyświetlenia Matplotlib.

Alternatywnie (zastrzeżenie: jeszcze tego nie próbowałem), możesz spróbować wytrawić figurę:

import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()
 7
Author: ptomato,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-05 07:58:26

Dobre pytanie. Oto tekst doc z pylab.save:

Pylab nie udostępnia już funkcji zapisu, choć stary pylab funkcja jest nadal dostępna jako matplotlib.mlab.Zapisz (możesz jeszcze zobacz w pylab jako " mlab.Zapisz"). Jednak dla zwykłego tekstu pliki, polecamy numpy.savetxt. Do zapisywania tablic numpy, polecamy numpy.save, i jego analogowe numpy.obciążenia, które są dostępny w pylab jako np.save I np.ładuj.

 1
Author: Steve Tjoa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-03 18:59:44

Wymyśliłem stosunkowo prosty sposób (ale nieco niekonwencjonalny), aby zapisać moje figury matplotlib. To działa 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 definiowanie funkcji save_plot w ten sposób (lepsza wersja przy użyciu kompresji zip do tworzenia lżejszych plików rysunkowych):

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 wykorzystuje mój własny moduł libscript, który głównie opiera się na modułach inspect i ast. Mogę spróbować udostępnić go na Githubie Jeśli zainteresowanie jest wyrażane (najpierw wymagałoby to trochę czyszczenia i mnie, aby zacząć z Github).

Idea stojąca za tą funkcją save_plot i modułem libscript polega na pobieraniu instrukcji Pythona, które tworzą figurę (używając modułu inspect), analizowaniu ich (używając modułu ast) w celu wyodrębnienia wszystkich zmiennych, funkcji i modułów, na których opiera się, wyodrębnienia ich z kontekstu wykonywania i serializacji ich jako instrukcji Pythona (kod zmiennych będzie podobny do t=[0.0,2.0,0.01])... oraz kod dla modułów będzie jak import matplotlib.pyplot as plt...). Wynikowe instrukcje Pythona są zapisywane jako skrypt Pythona, którego wykonanie spowoduje odtworzenie oryginalnej figury matplotlib.

Jak można sobie wyobrazić, działa to dobrze dla większości (jeśli nie wszystkich) figur matplotlib.

 0
Author: Astrum42,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-14 15:08:21