Сохранение интерактивных фигур Matplotlib - PullRequest
102 голосов
/ 03 декабря 2010

Есть ли способ сохранить фигуру Matplotlib, чтобы ее можно было снова открыть и восстановить типичное взаимодействие? (Как в формате .fig в MATLAB?)

Я часто запускаю одни и те же сценарии для создания этих интерактивных фигур. Или я посылаю своим коллегам несколько статических файлов PNG, чтобы показать различные аспекты сюжета. Я бы лучше отправил объект рисунка, чтобы они сами с ним взаимодействовали.

Ответы [ 6 ]

45 голосов
/ 30 января 2016

Я только что узнал, как это сделать. Упомянутая @pelson «экспериментальная поддержка соления» работает очень хорошо.

Попробуйте это:

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

После интерактивной настройки сохраните объект рисунка в виде двоичного файла:

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

Позже, откройте фигуру, и твики должны быть сохранены, а интерактивность GUI должна присутствовать:

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

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

Вы даже можете извлечь данные из графиков:

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

(работает для строк, pcolor & imshow - pcolormesh работает с некоторыми хитростями для восстановления сглаженных данных .)

Я получил отличный совет от Сохранение фигур Matplotlib с помощью Pickle .

38 голосов
/ 04 октября 2012

Начиная с Matplotlib 1.2, у нас теперь есть экспериментальная поддержка pickle . Попробуйте и посмотрите, хорошо ли это работает в вашем случае. Если у вас есть какие-либо проблемы, сообщите нам об этом в списке рассылки Matplotlib или открыв номер на github.com / matplotlib / matplotlib .

22 голосов
/ 03 декабря 2010

Это была бы отличная функция, но AFAIK она не реализована в Matplotlib и, вероятно, будет трудно реализовать самостоятельно из-за способа хранения фигур.

Я быпредложите либо (а) отдельную обработку данных от генерации рисунка (который сохраняет данные с уникальным именем) и написание сценария генерации рисунка (загрузка указанного файла сохраненных данных) и редактирования по своему усмотрению, либо (б) сохранить какPDF / SVG / PostScript отформатируйте и отредактируйте в каком-нибудь необычном редакторе фигур, например Adobe Illustrator (или Inkscape ).

РЕДАКТИРОВАТЬ пост осени 2012 : Как уже отмечалось ниже (хотя упомянуто здесь, как это является принятым ответом), Matplotlib начиная с версии 1.2 позволил вам выбирать цифры.Поскольку в примечаниях к выпуску указано , это экспериментальная функция, которая не поддерживает сохранение фигуры в одной версии matplotlib и открытие в другой.Также обычно небезопасно восстанавливать рассол из ненадежного источника.

Для совместного использования / последующего редактирования графиков (которые в первую очередь требуют значительной обработки данных и, возможно, потребуется подправить через несколько месяцев, скажем, во время рецензирования для научной публикации), я все же рекомендую рабочий процесс (1) иметь обработку данныхсценарий, который перед созданием графика сохраняет обработанные данные (которые попадают в ваш график) в файл, и (2) имеет отдельный сценарий создания графика (который вы настраиваете по мере необходимости) для воссоздания графика.Таким образом, для каждого графика вы можете быстро запустить скрипт и заново сгенерировать его (и быстро скопировать настройки графика с новыми данными).Тем не менее, выбор фигуры может быть удобен для краткосрочного / интерактивного / исследовательского анализа данных.

7 голосов
/ 04 декабря 2010

Почему бы просто не отправить скрипт Python?Файлы .fig MATLAB требуют, чтобы получатель имел MATLAB для их отображения, что эквивалентно отправке скрипта Python, для которого требуется отображение Matplotlib.

В качестве альтернативы (отказ от ответственности: я еще не пробовал), вы могли быпопробуйте засечь цифру:

import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()
1 голос
/ 03 декабря 2010

Хороший вопрос. Вот текст документа от pylab.save:

pylab больше не предоставляет функцию сохранения, хотя старый pylab функция по-прежнему доступна как matplotlib.mlab.save (вы все еще можете называйте это в pylab как "mlab.save"). Однако для простого текста файлы, мы рекомендуем numpy.savetxt. Для сохранения массивов NumPy, мы рекомендуем numpy.save и его аналог numpy.load, которые доступно в pylab как np.save и np.load.

0 голосов
/ 07 ноября 2017

Я нашел относительно простой способ (хотя и немного нетрадиционный), чтобы сохранить мои цифры matplotlib. Это работает так:

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()))

с функцией save_plot, определенной следующим образом (простая версия для понимания логики):

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'

или определение функции save_plot следующим образом (лучшая версия, использующая сжатие zip для получения более легких файлов рисунков):

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'

Для этого используется мой собственный модуль libscript, который в основном использует модули inspect и ast. Я могу попытаться поделиться им на Github, если будет проявлен интерес (для этого сначала потребуется некоторая очистка, и я начну с Github).

Идея этой функции save_plot и модуля libscript заключается в том, чтобы получить инструкции Python, которые создают фигуру (с помощью модуля inspect), проанализировать их (используя модуль ast), чтобы извлечь все переменные, функции и импорт модулей, на которые он опирается, извлечение их из контекста выполнения и сериализация их в виде инструкций Python (код для переменных будет выглядеть как t=[0.0,2.0,0.01] ..., а код для модулей будет выглядеть как import matplotlib.pyplot as plt ...) с добавлением к инструкциям на рисунке. , Полученные инструкции Python сохраняются в виде сценария Python, выполнение которого перестроит исходную фигуру matplotlib.

Как вы можете себе представить, это хорошо работает для большинства (если не для всех) фигур matplotlib.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...