Сохранение интерактивных фигур Matplotlib
Есть ли способ сохранить фигуру Matplotlib, чтобы ее можно было снова открыть и восстановить типичное взаимодействие? (Как формат.fig в MATLAB?)
Я часто запускаю одни и те же сценарии для создания этих интерактивных фигур. Или я посылаю своим коллегам несколько статических файлов PNG, чтобы показать различные аспекты сюжета. Я бы лучше отправил объект рисунка, чтобы они сами с ним взаимодействовали.
7 ответов
Это было бы отличной возможностью, но AFAIK она не реализована в Matplotlib и, вероятно, будет трудно реализовать самостоятельно из-за способа хранения фигур.
Я бы предложил (а) отдельно обработать данные от генерации рисунка (который сохраняет данные с уникальным именем) и написать скрипт генерации рисунка (загрузка указанного файла сохраненных данных) и редактировать по своему усмотрению или (b) сохранить в формате PDF / SVG / PostScript и отредактировать в каком-нибудь необычном редакторе рисунков, таком как Adobe Illustrator (или Inkscape).
РЕДАКТИРОВАТЬ пост осени 2012 года: как другие отметили ниже (хотя упомянуто здесь, поскольку это принятый ответ), Matplotlib, начиная с версии 1.2, позволяет вам выбирать цифры. Как говорится в примечаниях к выпуску, это экспериментальная функция, которая не поддерживает сохранение фигуры в одной версии matplotlib и открытие в другой. Также обычно небезопасно восстанавливать рассол из ненадежного источника.
Для совместного использования / последующего редактирования графиков (которые в первую очередь требуют значительной обработки данных и, возможно, потребуется настроить несколько месяцев спустя, например, во время рецензирования для научной публикации), я все же рекомендую, чтобы рабочий процесс (1) имел сценарий обработки данных, который до создания графика сохраняет обработанные данные (которые попадают в ваш график) в файл и (2) имеет отдельный сценарий создания графика (который вы настраиваете по мере необходимости) для воссоздания графика. Таким образом, для каждого графика вы можете быстро запустить скрипт и заново сгенерировать его (и быстро скопировать настройки графика с новыми данными). Тем не менее, выбор фигуры может быть удобен для краткосрочного / интерактивного / исследовательского анализа данных.
Я только что узнал, как это сделать. Упомянутая @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 с помощью рассола.
Начиная с Matplotlib 1.2, у нас теперь есть экспериментальная поддержка соления. Попробуйте и посмотрите, хорошо ли это работает в вашем случае. Если у вас есть какие-либо проблемы, пожалуйста, сообщите нам об этом в списке рассылки Matplotlib или открыв выпуск на https://github.com/matplotlib/matplotlib.
Почему бы просто не отправить скрипт Python? Файлы.fig MATLAB требуют, чтобы получатель имел MATLAB для их отображения, что эквивалентно отправке скрипта Python, который требует отображения Matplotlib.
В качестве альтернативы (заявление об отказе от ответственности: я еще не пробовал), вы можете попробовать засечь цифру:
import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()
Хороший вопрос. Вот текст документа от pylab.save
:
pylab больше не предоставляет функцию сохранения, хотя старая функция pylab все еще доступна как matplotlib.mlab.save (вы все равно можете ссылаться на нее в pylab как "mlab.save"). Однако для простых текстовых файлов мы рекомендуем numpy.savetxt. Для сохранения массивов numpy мы рекомендуем numpy.save и его аналог numpy.load, которые доступны в pylab как np.save и np.load.
Если вы хотите сохранить графики python в виде интерактивной фигуры для изменения и обмена с другими, например файл MATLAB .fig, вы можете попробовать использовать следующий код. Здесь
z_data.values
это просто пустой ndarray, поэтому вы можете использовать тот же код для построения и сохранения ваших собственных данных. Тогда нет необходимости использовать панд.
Сгенерированный здесь файл может быть открыт и интерактивно изменен любым пользователем с Python или без него, просто щелкнув его и открыв в браузерах, таких как Chrome/Firefox/Edge и т. д.
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='Mt Bruno Elevation', autosize=False,
width=500, height=500,
margin=dict(l=65, r=50, b=65, t=90))
fig.show()
fig.write_html("testfile.html")
Я нашел относительно простой способ (хотя и немного нетрадиционный), чтобы сохранить мои цифры 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.