대화 형 Matplotlib 그림 저장


119

다시 열 수 있고 일반적인 상호 작용을 복원 할 수 있도록 Matplotlib 그림을 저장하는 방법이 있습니까? (MATLAB의 .fig 형식과 비슷합니까?)

이러한 대화 형 그림을 생성하기 위해 동일한 스크립트를 여러 번 실행하고 있습니다. 또는 동료들에게 여러 개의 정적 PNG 파일을 보내 플롯의 다양한 측면을 보여줍니다. 차라리 피겨 객체를 보내고 그들 스스로 상호 작용하게하고 싶습니다.

답변:


30

이것은 훌륭한 기능이지만 AFAIK는 Matplotlib에서 구현되지 않으며 수치가 저장되는 방식으로 인해 직접 구현하기 어려울 수 있습니다.

(a) 그림 생성 (고유 한 이름으로 데이터 저장)에서 데이터 처리를 분리하고 그림 생성 스크립트 (저장된 데이터의 지정된 파일로드)를 작성하고 적합하다고 생각되는대로 편집하거나 (b ) PDF / SVG / PostScript 형식으로 저장하고 Adobe Illustrator (또는 Inkscape ) 와 같은 멋진 그림 편집기에서 편집 합니다.

편집 게시물 Fall 2012 : 다른 사람들이 아래에서 지적했듯이 (허용되는 답변으로 여기에 언급했지만) 버전 1.2 이후 Matplotlib를 사용하면 수치를 피클 할 수 있습니다. 는 AS 릴리스 노트 상태 , 그것은 실험적인 기능이며 다른 하나 개하기 matplotlib 버전과 구멍에 그림을 저장하는 지원하지 않습니다. 신뢰할 수없는 소스에서 피클을 복원하는 것도 일반적으로 안전하지 않습니다.

플롯을 공유 / 나중에 편집하려면 (먼저 중요한 데이터 처리가 필요하고 몇 달 후에 과학 간행물에 대한 동료 검토 중에 수정해야 할 수 있음) 플롯을 생성하기 전에 (1)의 워크 플로를 사용하는 것이 좋습니다. 처리 된 데이터 (플롯으로 이동)를 파일에 저장하고 (2) 별도의 플롯 생성 스크립트 (필요에 따라 조정)를 사용하여 플롯을 다시 만듭니다. 이렇게하면 각 플롯에 대해 스크립트를 빠르게 실행하고 다시 생성 할 수 있습니다 (새 데이터로 플롯 설정을 빠르게 복사). 즉, 수치를 산세하는 것은 단기 / 대화 형 / 탐색 데이터 분석에 편리 할 수 ​​있습니다.


2
이것이 구현되지 않은 것에 다소 놀랐습니다.하지만 좋습니다. 처리 된 데이터를 중간 파일에 저장하고이를 동료에게 플로팅하기위한 스크립트와 함께 보내겠습니다. 감사.
Matt

2
구현이 어렵다고 생각하므로 MATLAB이 제대로 작동하지 않습니다. 내가 그것을 사용했을 때, 수치는 MATLAB을 충돌시키는 데 사용되었으며 약간 다른 버전조차도 서로 .fig 파일을 읽을 수 없었습니다.
Adrian Ratnapala

6
pickle이제 MPL 수치에서 작동하므로 이는 거의 Matlab ".fig"그림 파일과 같이 수행 할 수 있고 적절하게 작동하는 것처럼 보입니다. 수행 방법에 대한 예는 아래 내 대답을 참조하십시오 (지금은?).
Demis

@Demis : ptomato가 아래 답변에서 지적했듯이 이미 그 당시에 존재했습니다.
strpeter

@strpeter-Matlab 수치는 이 주석 에서 지적한 것처럼 2010 년에 피클 할 수 없었습니다 . 실험 기능은 2012 년 가을에 출시 된 matplotlib 1.2 와 함께 추가되었습니다 . 거기에서 언급했듯이 matplotlib 버전간에 작동 할 것으로 기 대해서는 안되며 신뢰할 수없는 소스에서 가져온 피클을 열지 않아야합니다.
jimbob 박사는

63

이 작업을 수행하는 방법을 방금 찾았습니다. @pelson이 언급 한 "실험적 피클 지원"은 매우 잘 작동합니다.

이 시도:

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

대화 형 조정 후 Figure 개체를 이진 파일로 저장합니다.

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는 평면화 된 데이터를 재구성하는 몇 가지 트릭과 함께 작동합니다 .)

Pickle을 사용하여 Matplotlib Figures 저장 에서 훌륭한 팁을 얻었습니다 .


나는 이것이 버전 변경 등에 강력하지 않으며 py2.x와 py3.x간에 상호 호환되지 않는다고 생각합니다. 또한 pickle문서에 객체가 피클 (저장)되었을 때와 유사하게 환경을 설정해야한다고 명시되어 있지만 import matplotlib.pyplot as plt피클 링 (로드) 할 때 필요하지 않다는 것을 발견 했습니다. 피클 파일에 import 문을 저장합니다. .
Demis

5
열린 파일을 닫는 것을 고려해야합니다. 예with open('FigureObject.fig.pickle', 'rb') as file: figx = pickle.load(file)
strpeter

1
난 그냥 얻는다 : 'AttributeError :'Figure 'object has no attribute'_cachedRenderer '
user2673238

스크립트가 계속되는 것을 원하지 않고 아마도 바로 후에 종료되는 것을 원하지 않는다면 figx.show(), plt.show()대신 블로킹을 호출해야합니다 .
maechler

38

Matplotlib 1.2부터 실험적인 피클 지원이 제공됩니다. 그것을 시도하고 그것이 당신의 경우에 잘 작동하는지 확인하십시오. 문제가있는 경우 Matplotlib 메일 링리스트 또는 github.com/matplotlib/matplotlib 에서 문제를 열어 알려주십시오 .


2
이 유용한 기능이 그림의 "다른 이름으로 저장"자체에 추가 될 수있는 이유입니다. .pkl을 추가 하시겠습니까?
dashesy

@dashesy 좋은 아이디어. 당신이 그것을 구현하고 싶다면 그것을 지원할 것입니까?
pelson 2014 년

1
백엔드의 하위 집합에서만 작동합니까? OSX에서 간단한 그림을 피클하려고하면 PicklingError: Can't pickle <type '_macosx.GraphicsContext'>: it's not found as _macosx.GraphicsContext.
farenorth 2015 년

위의 PicklingError경우 plt.show()피클을 수행하기 전에 전화를 거는 경우에만 발생합니다 . 그러니 그냥 배치 plt.show()pickle.dump().
salomonvh

MacOS 10.11의 py3.5에서는 순서 fig.show()가 중요하지 않은 것 같습니다. 버그가 수정되었을 수 있습니다. 나는 show()문제없이 전후에 피클을 할 수 있습니다 .
Demis

7

왜 파이썬 스크립트를 보내지 않습니까? MATLAB의 .fig 파일은 수신자에게 MATLAB이이를 표시하도록 요구하므로 표시하는 데 Matplotlib가 필요한 Python 스크립트를 보내는 것과 거의 같습니다.

또는 (면책 조항 : 아직 시도하지 않았습니다) 그림을 피클 링 할 수 있습니다.

import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()

3
안타깝게도 matplotlib 수치는 피클 할 수 없으므로 이러한 접근 방식은 작동하지 않습니다. 이면에는 피클 링을 지원하지 않는 C 확장이 너무 많습니다. 나는 스크립트 + 데이터를 보내는 것에 전적으로 동의합니다. 저는 matlab에 저장된 .fig의 요점을 본 적이없는 것 같아서 사용하지 않았습니다. 어쨌든 누군가에게 독립 실행 형 코드와 데이터를 보내는 것은 내 경험상 장기적으로 가장 쉬운 일이었습니다. 그래도 matplotlib의 피클 객체가 피클 가능하다면 좋을 것입니다.
Joe Kington

1
전처리 된 데이터조차도 다소 크고 플로팅 절차가 복잡합니다. 그래도 유일한 의지처럼 보입니다. 감사.
Matt

1
피규어는 이제 피클이 가능합니다. 꽤 잘 작동합니다! 아래 예.
Demis

피클의 이점은 모든 그림 / 서브 플롯 간격 / 위치를 프로그래밍 방식으로 조정할 필요가 없다는 것입니다. MPL 플롯의 GUI를 사용하여 그림을 멋지게 보이게 한 다음 MyPlot.fig.pickle파일 을 저장 하여 나중에 필요에 따라 플롯 프레젠테이션을 조정할 수 있습니다. 이것은 또한 Matlab의 .fig파일 의 장점이기도 합니다. 무화과의 크기 / 가로 세로 비율을 변경해야 할 때 특히 유용합니다 (프레젠테이션 / 종이에 삽입).
Demis

1

좋은 질문. 다음은의 문서 텍스트입니다 pylab.save.

이전 pylab 함수는 여전히 matplotlib.mlab.save로 사용할 수 있지만 pylab은 더 이상 저장 기능을 제공하지 않습니다 (pylab에서 "mlab.save"로 계속 참조 할 수 있음). 그러나 일반 텍스트 파일의 경우 numpy.savetxt를 권장합니다. numpy 배열을 저장하려면 numpy.save 및 pylab에서 np.save 및 np.load로 사용할 수있는 아날로그 numpy.load를 권장합니다.


이렇게하면 pylab 객체의 데이터가 저장되지만 Figure를 다시 생성 할 수는 없습니다.
박사 jimbob

옳은. 나는 그 대답이 사용을 권장하는 것이 아니라는 것을 분명히해야한다 pylab.save. 사실, 문서 텍스트를 보면 그것을 사용 해서는 안되는 것 같습니다.
Steve Tjoa 2010

3D 그림을 보내는 외부 방법이 있습니까? 간단한 GUI
로도 실행 가능

0

나는 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대부분의 모듈에 의존하는, 내 자신의 inspectast. 관심이 있으면 Github에서 공유해 볼 수 있습니다 (먼저 정리가 필요하고 Github를 시작하려면 제가 필요합니다).

save_plot함수와 libscript모듈의 이면에있는 아이디어 는 Figure를 생성 (module 사용 inspect)하고 분석 (module 사용 ast)하여 모든 변수, 함수 및 모듈 가져 오기를 추출하고 실행 컨텍스트에서이를 추출하고 직렬화 하는 Python 명령어를 가져 오는 것입니다. 파이썬 명령어 (변수에 대한 코드는 t=[0.0,2.0,0.01]...와 같고 모듈에 대한 코드는 ...와 같음 import matplotlib.pyplot as plt)로 그림 명령어 앞에 추가됩니다. 결과 python 명령어는 실행이 원래 matplotlib 그림을 다시 빌드하는 python 스크립트로 저장됩니다.

상상할 수 있듯이 이것은 대부분의 (전부는 아니지만) matplotlib 그림에서 잘 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.