Matplotlib ile engellemesiz bir şekilde çizim yapmak


140

Son birkaç gündür Numpy ve matplotlib ile oynuyorum. Matplotlib'i çalıştırmayı engellemeden bir işlev çizmeye çalışırken sorun yaşıyorum. SO'da zaten benzer sorular soran birçok ileti dizisi olduğunu biliyorum ve epeyce Google'da arama yaptım ama bu işi yapmayı başaramadım.

Bazılarının önerdiği gibi show (blok = False) kullanmayı denedim, ancak aldığım tek şey donmuş bir pencere. Sadece show () 'u çağırırsam, sonuç doğru şekilde çizilir, ancak pencere kapanana kadar çalıştırma engellenir. Okuduğum diğer konulardan, show'un (block = False) çalışıp çalışmayacağının arka uca bağlı olduğundan şüpheleniyorum. Bu doğru mu? Arka ucum Qt4Agg. Koduma bakıp yanlış bir şey görürsen bana söyleyebilir misin? İşte kodum. Herhangi bir yardım için teşekkürler.

from math import *
from matplotlib import pyplot as plt
print plt.get_backend()



def main():
    x = range(-50, 51, 1)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4

        y = [Xi**pow for Xi in x]
        print y

        plt.plot(x, y)
        plt.draw()
        #plt.show()             #this plots correctly, but blocks execution.
        plt.show(block=False)   #this creates an empty frozen window.
        _ = raw_input("Press [enter] to continue.")


if __name__ == '__main__':
    main()

PS. Her seferinde yeni bir tane oluşturmak yerine mevcut pencereyi güncellemek istediğimi söylemeyi unuttum.


1
matplotlib etkileşimli modunu daha plt.ion()önce denediniz plt.show()mi? Her arsa bir çocuk iş parçacığına dönüştüğü için engelleyici olmamalıdır.
Anzel

@Anzel Daha yeni denedim, ama bir fark yaratmıyor gibi görünüyor.
opetroch

3
Komut dosyanızı nasıl çalıştırıyorsunuz? Örnek kodunuzu terminal / komut isteminden çalıştırırsam, iyi çalışıyor gibi görünüyor, ancak geçmişte IPython QtConsole veya IDE'lerden böyle şeyler yapmaya çalışırken sorun yaşadığımı düşünüyorum.
Marius 15

1
@Marius Aha !! Haklısın. Aslında onu IDE'min (PyCharm) konsolundan çalıştırıyorum. Cmd komut isteminden çalıştırırken, plt.show (block = False) iyi çalışıyor! Size herhangi bir fikir / çözüm bulup bulmadığınızı sorarsam çok mu soracağım? Çok teşekkürler!
opetroch

Üzgünüm gerçekten bilmiyorum. Matplotlib'in konsolla nasıl etkileşim kurduğunun ayrıntılarını gerçekten anlamıyorum, bu yüzden bu şeyleri yapmam gerekirse genellikle komut isteminden çalıştırmaya geçiyorum matplotlib.
Marius

Yanıtlar:


167

Uzun süre çözüm arayışına girdim ve bu cevabı buldum .

Görünüşe göre, senin (ve ben) istediğini elde etmek için plt.ion(), plt.show()(ile değil block=False) ve en önemlisi plt.pause(.001)(veya ne zaman istersen) kombinasyonuna ihtiyacın var . Duraklama ana kod çizim dahil uyurken GUI olaylar olur çünkü ihtiyaç vardır. Bunun uyku ipliğinden zaman alarak uygulanması mümkündür, bu yüzden belki IDE'ler bunu karıştırır - bilmiyorum.

İşte benim için python 3.5'te çalışan bir uygulama:

import numpy as np
from matplotlib import pyplot as plt

def main():
    plt.axis([-50,50,0,10000])
    plt.ion()
    plt.show()

    x = np.arange(-50, 51)
    for pow in range(1,5):   # plot x^1, x^2, ..., x^4
        y = [Xi**pow for Xi in x]
        plt.plot(x, y)
        plt.draw()
        plt.pause(0.001)
        input("Press [enter] to continue.")

if __name__ == '__main__':
    main()

3
Cevabınız, yaşadığım benzer bir sorunu çözmemde bana çok yardımcı oldu. Daha önce plt.drawtakip ettim plt.show(block = False)ama sonra çalışmayı durdurdu: Şekil yanıt vermiyor, kapatılıyor iPython'u çökertiyordu. Benim çözümüm, her örneğini kaldırıp plt.draw()yerine koymaktı plt.pause(0.001). Bunu daha önce olduğu plt.show(block = False)gibi takip plt.drawettirmek yerine, öncesinde plt.ion()ve vardı plt.show(). Şimdi bir var MatplotlibDeprecationWarningama rakamlarımı çizmeme izin verdi, bu yüzden bu çözümden memnunum.
blue_chip

3
Python 2.7'de kullanmamanız gerektiğini raw_inputunutmayın input. Buraya
Chris

Reaktif "canlandırma" yaklaşımı mümkün olmadığında gerçekten yararlı bir çözüm! Kullanımdan kaldırma uyarısından nasıl kurtulacağını bilen var mı?
Frederic Fortier

Lütfen birisi bana plt.show'dan önce plt.ion eklemeye çalıştığımda neden bir donma komut istemi aldığımı söyleyebilir mi?
Gabriel Augusto

@GabrielAugusto Buna neyin sebep olabileceğinden emin değilim ve ne demek istediğinizden tam olarak emin değilim. Bu örneği Python 3.6'da test ettim ve hala çalışıyor. Aynı modeli kullandıysanız ve donuyorsa, kurulumunuzda bir sorun olabilir. Önce normal çizimin işe yarayıp yaramadığını kontrol etmelisiniz. Farklı bir şey denediyseniz, yorumlarda bununla ilgili yapacak pek bir şey yok. Her iki durumda da, ayrı bir soru sormayı düşünebilirsiniz.
krs013

23

Benim için çalışan basit bir numara şudur:

  1. Show içinde block = False argüman kullanın : plt.show (block = False)
  2. .Py betiğinin sonunda başka bir plt.show () kullanın .

Örnek :

import matplotlib.pyplot as plt

plt.imshow(add_something)
plt.xlabel("x")
plt.ylabel("y")

plt.show(block=False)

#more code here (e.g. do calculations and use print to see them on the screen

plt.show()

Not : plt.show()betiğimin son satırıdır.


8
Bu (Linux, Anaconda, Python 2.7, varsayılan arka uç üzerinde, benim için) üretir boş nihayet doldurulur alır yürütme, en sonuna kadar boş kalır pencerenin. Yürütme ortasında bir arsa güncellenmesi için yararlı değil. :-(
sh37211

@ sh37211 Hedefinizin ne olduğundan emin değilim. Bazı durumlarda bir şeyi çizmeye çalıştığınızda, ancak plot komutundan sonra başka komutlara sahip olursunuz, o zaman bu, diğer komutları çizmenize ve çalıştırmanıza izin verdiği için kullanışlıdır. Bununla ilgili daha fazla bilgi için bu gönderiye bakın: stackoverflow.com/questions/458209/… . Bir grafiği güncellemek istiyorsanız, başka bir yol olmalıdır.
seralouk

17

Grafiği bir diziye yazıp ardından diziyi farklı bir iş parçacığında görüntüleyerek yürütmeyi engellemekten kaçınabilirsiniz. Burada pyformulas 0.2.8'den pf.screen kullanarak aynı anda grafik oluşturma ve görüntüleme örneği verilmiştir :

import pyformulas as pf
import matplotlib.pyplot as plt
import numpy as np
import time

fig = plt.figure()

canvas = np.zeros((480,640))
screen = pf.screen(canvas, 'Sinusoid')

start = time.time()
while True:
    now = time.time() - start

    x = np.linspace(now-2, now, 100)
    y = np.sin(2*np.pi*x) + np.sin(3*np.pi*x)
    plt.xlim(now-2,now+1)
    plt.ylim(-3,3)
    plt.plot(x, y, c='black')

    # If we haven't already shown or saved the plot, then we need to draw the figure first...
    fig.canvas.draw()

    image = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
    image = image.reshape(fig.canvas.get_width_height()[::-1] + (3,))

    screen.update(image)

#screen.close()

Sonuç:

Sinüs animasyonu

Sorumluluk reddi: Pyformulas'ın bakıcısıyım.

Referans: Matplotlib: grafiği numpy dizisine kaydet


9

Bu cevapların çoğu aşırı şişirilmiş ve bulabildiğim kadarıyla cevabı anlamak o kadar da zor değil.

İsterseniz kullanabilirsiniz plt.ion(), ancak ben de plt.draw()aynı derecede etkili buldum

Benim özel projem için görüntüleri çiziyorum, ama sen plot()ya scatter()da ya da onun yerine kullanabilirsin figimage(), önemli değil.

plt.figimage(image_to_show)
plt.draw()
plt.pause(0.001)

Veya

fig = plt.figure()
...
fig.figimage(image_to_show)
fig.canvas.draw()
plt.pause(0.001)

Gerçek bir figür kullanıyorsanız.
Bunu çözmek için @ krs013 ve @Default Picture'ın cevaplarını kullandım
Umarım bu, birini her figürü ayrı bir başlıkta yayınlamaktan veya sadece bunu anlamak için bu romanları okumak zorunda kalmaktan kurtarır.


3

Canlı Çizim

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
# plt.axis([x[0], x[-1], -1, 1])      # disable autoscaling
for point in x:
    plt.plot(point, np.sin(2 * point), '.', color='b')
    plt.draw()
    plt.pause(0.01)
# plt.clf()                           # clear the current figure

veri miktarı çok fazlaysa, basit bir sayaçla güncelleme hızını düşürebilirsiniz

cnt += 1
if (cnt == 10):       # update plot each 10 points
    plt.draw()
    plt.pause(0.01)
    cnt = 0

Program Çıkışından Sonra Grafiği Bekletme

Tatmin edici cevap bulamayan asıl sorunum buydu, senaryo bittikten sonra kapanmayan bir çizim yapmak istedim (MATLAB gibi),

Bunu düşünürseniz, betik bittikten sonra program sonlandırılır ve grafiği bu şekilde tutmanın mantıklı bir yolu yoktur, bu nedenle iki seçenek vardır.

  1. betiğin çıkmasını engelle (bu, plt.show () ve istediğim şey değil)
  2. arsa ayrı bir iş parçacığı üzerinde çalıştırın (çok karmaşık)

bu benim için tatmin edici değildi, bu yüzden kutunun dışında başka bir çözüm buldum

SaveToFile ve harici görüntüleyicide Görüntüle

Bunun için kaydetme ve görüntüleme hem hızlı olmalı hem de görüntüleyen kişi dosyayı kilitlememeli ve içeriği otomatik olarak güncellemelidir.

Kaydetmek İçin Format Seçme

vektör tabanlı formatlar hem küçük hem de hızlıdır

  • SVG iyidir, ancak varsayılan olarak manuel yenileme gerektiren web tarayıcısı dışında bunun için iyi bir görüntüleyici bulamaz.
  • PDF , vektör formatlarını destekleyebilir ve canlı güncellemeyi destekleyen hafif görüntüleyiciler vardır

Canlı Güncelleme ile Hızlı Hafif Görüntüleyici

İçin PDF birkaç iyi seçenek vardır

  • Windows'ta ücretsiz, hızlı ve hafif olan SumatraPDF kullanıyorum (benim durumum için yalnızca 1,8 MB RAM kullanıyor)

  • Linux'ta Evince (GNOME) ve Ocular (KDE) gibi birkaç seçenek vardır.

Örnek Kod ve Sonuçlar

Bir dosyaya çizim çıktısı almak için örnek kod

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(2 * x)
plt.plot(x, y)
plt.savefig("fig.pdf")

İlk çalıştırmadan sonra, çıktı dosyasını yukarıda belirtilen görüntüleyicilerden birinde açın ve keyfini çıkarın.

İşte SumatraPDF ile birlikte VSCode'un bir ekran görüntüsü, ayrıca süreç yarı canlı güncelleme oranı elde etmek için yeterince hızlı (sadece time.sleep()aralıklar arasında kurulumumda 10Hz'e yaklaşabilirim ) pyPlot, Sigara Engelleme


2

Iggy'nin cevabı benim için takip etmesi en kolay olanıydı , ancak subplotsadece yaptığım sırada orada olmayan bir sonraki komutu yaparken aşağıdaki hatayı aldım show:

MatplotlibDeprecationWarning: Önceki eksenlerle aynı bağımsız değişkenleri kullanarak bir eksen eklemek şu anda önceki örneği yeniden kullanıyor. Gelecekteki bir sürümde, her zaman yeni bir örnek oluşturulacak ve döndürülecektir. Bu arada, her eksen örneğine benzersiz bir etiket geçirilerek bu uyarı bastırılabilir ve gelecekteki davranış sağlanabilir.

Bu hatayı önlemek için , kullanıcı girdikten sonra arsa kapatmaya (veya temizlemeye ) yardımcı olur .

İşte benim için çalışan kod:

def plt_show():
    '''Text-blocking version of plt.show()
    Use this instead of plt.show()'''
    plt.draw()
    plt.pause(0.001)
    input("Press enter to continue...")
    plt.close()

0

Çizilen Python paketi, bir grafiği gerçek zamanlı olarak engellemesiz bir şekilde güncellemeye izin verir.
Ayrıca, örneğin her kare için ölçüleri çizmek için bir web kamerası ve OpenCV ile çalışır. Orijinal gönderiye
bakın .

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.