Etkileşimli Matplotlib figürlerini kaydetme


119

Bir Matplotlib figürünü yeniden açılabilecek ve tipik etkileşimi geri yükleyebilecek şekilde kurtarmanın bir yolu var mı? (MATLAB'daki .fig biçimi gibi mi?)

Bu etkileşimli figürleri oluşturmak için kendimi birçok kez aynı senaryoları çalıştırırken buluyorum. Ya da bir grafiğin farklı yönlerini göstermek için meslektaşlarıma birden çok statik PNG dosyası gönderiyorum. Figür nesnesini göndermeyi ve kendilerinin onunla etkileşime girmelerini tercih ederim.

Yanıtlar:


30

Bu harika bir özellik olurdu, ancak AFAIK Matplotlib'de uygulanmıyor ve rakamların saklanma şekli nedeniyle muhtemelen kendiniz uygulamak zor olacaktır.

Ya (a) verilerin işlenmesini şekil oluşturmadan ayırmanızı (verileri benzersiz bir adla kaydeder) ve komut dosyası üreten bir şekil yazmanızı (kaydedilen verilerin belirli bir dosyasını yükleyerek) ve uygun gördüğünüz şekilde düzenlemenizi veya (b ) PDF / SVG / PostScript formatında kaydedin ve Adobe Illustrator (veya Inkscape ) gibi bazı süslü şekil düzenleyicide düzenleyin .

Güz 2012 sonrası DÜZENLE : Aşağıda diğerlerinin de belirttiği gibi (burada kabul edilen cevap bu olarak belirtilse de), Matplotlib sürüm 1.2'den bu yana rakamları karıştırmanıza izin verdi. Gibi sürüm notları devlet , bu deneysel bir özelliktir ve başka bir matplotlib sürümü ve açılma bir rakam tasarruf desteklemez. Ayrıca, güvenilmeyen bir kaynaktan bir turşuyu geri yüklemek genellikle güvensizdir.

Grafikleri paylaşmak / daha sonra düzenlemek için (önce önemli veri işlemeyi gerektiren ve aylar sonra bilimsel bir yayın için meslektaş incelemesi sırasında ince ayar yapılması gerekebilir) için, yine de (1) iş akışının bir olay örgüsü oluşturmadan önce bir veri işleme komut dosyasına sahip olmasını öneriyorum. işlenmiş verileri (arsa içine giren) bir dosyaya kaydeder ve (2) grafiği yeniden oluşturmak için ayrı bir çizim oluşturma komut dosyasına (gerektiğinde ayarladığınız) sahip olur. Bu şekilde, her çizim için hızlı bir şekilde bir komut dosyası çalıştırabilir ve yeniden oluşturabilirsiniz (ve çizim ayarlarınızı yeni verilerle hızlıca kopyalayabilirsiniz). Bununla birlikte, bir figürün dekapajı kısa vadeli / etkileşimli / keşifsel veri analizi için uygun olabilir.


2
Bunun uygulanmaması biraz şaşırttı .. Ama tamam, işlenen verileri bir ara dosyaya kaydedeceğim ve bunu ve çizim için meslektaşlara bir komut dosyası göndereceğim. Teşekkürler.
Matt

2
Uygulamanın zor olduğundan şüpheleniyorum, bu yüzden bir MATLAB bu kadar kötü çalışıyor. Onu kullandığımda, MATLAB'ı çökertmek için kullanılan rakamlar ve hatta biraz farklı sürümler bile birbirlerinin .fig dosyalarını okuyamıyordu.
Adrian Ratnapala

6
pickleşimdi MPL rakamları üzerinde çalışıyor, bu yüzden bu yapılabilir ve makul bir şekilde iyi çalışıyor gibi görünüyor - neredeyse bir Matlab ".fig" şekil dosyası gibi. Nasıl yapılacağına dair bir örnek için aşağıdaki cevabıma bakın (şimdilik?).
Demis

@Demis: ptomato'nun aşağıdaki cevabında belirttiği gibi, o zamanlar zaten vardı.
strpeter

@strpeter - Matlab rakamları, bu yorumda belirtildiği gibi 2010 yılında seçilebilir değildi . Deneysel özellik 2012 Sonbaharında yayınlanan matplotlib 1.2 ile eklenmiştir . Orada belirtildiği gibi, matplotlib sürümleri arasında çalışmasını beklememelisiniz ve güvenilmeyen bir kaynaktan gelen turşuları açmamalısınız.
dr jimbob

64

Bunu nasıl yapacağımı yeni öğrendim. @Pelson'un bahsettiği "deneysel turşu desteği" oldukça iyi çalışıyor.

Bunu dene:

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

Etkileşimli ince ayarınızdan sonra, şekil nesnesini ikili dosya olarak kaydedin:

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

Daha sonra şekli açın ve ince ayarlar kaydedilmeli ve GUI etkileşimi mevcut olmalıdır:

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

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

Verileri grafiklerden bile çıkarabilirsiniz:

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

(Çizgiler, pcolor ve imshow için çalışır - pcolormesh, düzleştirilmiş verileri yeniden yapılandırmak için bazı hilelerle çalışır .)

Pickle Kullanarak Matplotlib Figürlerini Kurtarmaktan mükemmel bir ipucu aldım .


Bunun sürüm değişiklikleri vb. İçin sağlam olmadığına ve py2.x ve py3.x arasında çapraz uyumlu olmadığına inanıyorum. Ayrıca pickledokümantasyonun, nesnenin salamura edildiği (kaydedildiği) zamanki gibi ortamı ayarlamamız gerektiğini belirttiğini düşündüm , ancak import matplotlib.pyplot as pltçözerken (yüklerken) bunu yapmanıza gerek olmadığını fark ettim - bu, salamura dosyasında içe aktarma ifadelerini kaydeder .
Demis

5
Açık dosyaları kapatmayı düşünmelisiniz: örn.with open('FigureObject.fig.pickle', 'rb') as file: figx = pickle.load(file)
strpeter

1
Sadece şunu anlıyorum: 'AttributeError:' Şekil 'nesnesinin özniteliği yok' _cachedRenderer ''
user2673238

Betiğin devam etmesini ve muhtemelen hemen sonra sonlandırılmasını istemiyorsanız, bunun yerine figx.show()çağırmalısınız plt.show(), bu engelleme demektir.
maechler

38

Matplotlib 1.2'den itibaren artık deneysel turşu desteğimiz var. Bunu bir deneyin ve davanız için iyi çalışıp çalışmadığını görün. Herhangi bir sorununuz varsa, lütfen Matplotlib posta listesinde veya github.com/matplotlib/matplotlib adresinde bir sorun açarak bize bildirin .


2
Bu kullanışlı özelliğin herhangi bir nedenle figürün "Farklı kaydet" bölümüne eklenmesi olabilir. Belki .pkl ekleniyor?
2014

İyi fikir @dashesy. Uygulamaya bir şans vermek isteseydin, bunu desteklerdim.
pelson

1
Bu yalnızca arka uçların bir alt kümesinde mi çalışır? OSX'te basit bir figür seçmeye çalıştığımda, anlıyorum PicklingError: Can't pickle <type '_macosx.GraphicsContext'>: it's not found as _macosx.GraphicsContext.
farenorth

Yukarıdakiler PicklingErroryalnızca plt.show()turşu yapmadan önce ararsanız oluşur . Öyleyse hemen plt.show()sonrasına yerleştirin pickle.dump().
salomonvh

MacOS 10.11'deki py3.5'imde sıralaması fig.show()önemli görünmüyor - belki bu hata düzeltildi. Sorunsuz bir şekilde önce / sonra turşu yapabilirim show().
Demis

7

Neden Python betiğini göndermiyorsunuz? MATLAB'ın .fig dosyaları, alıcının bunları görüntülemek için MATLAB'a sahip olmasını gerektirir, bu nedenle bu, Matplotlib'in görüntülenmesini gerektiren bir Python betiği göndermeye eşdeğerdir.

Alternatif olarak (sorumluluk reddi: Bunu henüz denemedim), şekli dekapaj yapmayı deneyebilirsiniz:

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

3
Ne yazık ki, matplotlib rakamları zor durumda değil, bu yüzden bu yaklaşım işe yaramayacak. Perde arkasında dekapajı desteklemeyen çok fazla C uzantısı var. Yine de sadece komut dosyası + verilerini göndermeye tamamen katılıyorum ... Matlab'ın kaydedilen .fig dosyalarının noktasını gerçekten hiç görmedim, bu yüzden onları hiç kullanmadım. Birine bağımsız kod ve veri göndermek, deneyimlerime göre uzun vadede en kolayı oldu. Yine de, matplotlib'in figürü turşu haline getirilebilen nesneler olsa güzel olurdu.
Joe Kington

1
Önceden işlenmiş verilerimiz bile biraz büyük ve çizim prosedürü karmaşık. Tek başvuru yolu gibi görünüyor. Teşekkürler.
Matt

1
Görünüşe göre rakamlar artık seçilebilir - oldukça iyi çalışıyor! Aşağıdaki örnek.
Demis

Turşu yapmanın yararı, tüm şekil / alt grafik aralıklarını / konumlarını programlı olarak ayarlamanıza gerek olmamasıdır. Figürün güzel görünmesi vb. İçin MPL grafiğinin GUI'sini kullanabilir, ardından MyPlot.fig.pickledosyayı kaydederek gerektiğinde çizim sunumunu ayarlama yeteneğini koruyabilirsiniz. Matlab'ın .figdosyalarının harika yanı da budur . Özellikle incirin boyutunu / en boy oranını değiştirmeniz gerektiğinde (sunumlara / kağıtlara eklemek için) kullanışlıdır.
Demis

1

İyi soru. İşte doküman metni pylab.save:

pylab artık bir kaydetme işlevi sağlamaz, ancak eski pylab işlevi hala matplotlib.mlab.save olarak mevcuttur (yine de pylab'da "mlab.save" olarak adlandırabilirsiniz). Bununla birlikte, düz metin dosyaları için numpy.savetxt öneririz. Numpy dizilerini kaydetmek için, pylab'de np.save ve np.load olarak bulunan numpy.save ve analog numpy.load'u öneririz.


Bu, verileri bir pylab nesnesinden kaydeder, ancak şekli yeniden oluşturmanıza izin vermez.
dr jimbob

Doğru. Cevabın kullanılacak bir tavsiye olmadığını açıklığa kavuşturmalıyım pylab.save. Aslında, doc metinden, bir gerektiğini görünür değil kullanabilirsiniz.
Steve Tjoa

3D Şekil göndermek için harici bir yöntem var mı? Exe için basit bir GUI bile mümkün ..
CromeX

0

Matplotlib rakamlarımı kurtarmak için nispeten basit (ancak biraz alışılmadık) bir yol buldum. Şöyle çalışır:

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

şu şekilde save_plottanımlanmış işlev ile (mantığı anlamak için basit sürüm):

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'

veya save_plotbunun gibi tanımlayıcı işlev (daha hafif şekil dosyaları oluşturmak için zip sıkıştırması kullanan daha iyi sürüm):

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'

Bu, libscriptçoğunlukla modüllere inspectve ast. İlgi duyulursa bunu Github'da paylaşmayı deneyebilirim (önce biraz temizlik ve Github'a başlamam gerekir).

Bu save_plotişlev ve libscriptmodülün arkasındaki fikir , figürü oluşturan (modülü kullanarak inspect) python talimatlarını almak, bunları analiz etmek (modülü kullanarak ast), bağlı olduğu tüm değişkenleri, işlevleri ve modülleri almak, bunları yürütme bağlamından çıkarmak ve bunları serileştirmektir. python talimatları olarak (değişkenler için kod t=[0.0,2.0,0.01]... gibi olacaktır ve modüller için kod import matplotlib.pyplot as plt... gibi olacaktır ) şekil talimatlarının başına eklenmiştir. Ortaya çıkan python talimatları, yürütülmesi orijinal matplotlib figürünü yeniden oluşturacak bir python betiği olarak kaydedilir.

Tahmin edebileceğiniz gibi, bu matplotlib figürlerinin çoğu için (hepsi değilse de) işe yarar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.