Bawiłem się Numpy i matplotlib w ciągu ostatnich kilku dni. Mam problemy z utworzeniem funkcji wykresu matplotlib bez blokowania wykonywania. Wiem, że w SO jest już wiele wątków z podobnymi pytaniami, a ja sporo szukałem w Google, ale nie udało mi się tego zrobić.
Próbowałem użyć show (block = False), jak sugerują niektórzy, ale wszystko, co otrzymuję, to zamrożone okno. Jeśli po prostu wywołam show (), wynik zostanie poprawnie wykreślony, ale wykonanie zostanie zablokowane do momentu zamknięcia okna. Z innych wątków, które czytałem, podejrzewam, że to, czy show (blok = False) działa, czy nie, zależy od zaplecza. Czy to jest poprawne? Mój zaplecze to Qt4Agg. Czy mógłbyś rzucić okiem na mój kod i powiedzieć mi, czy coś jest nie tak? Oto mój kod. Dzięki za wszelką pomoc.
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. Zapomniałem powiedzieć, że chciałbym aktualizować istniejące okno za każdym razem, gdy coś wykreślam, zamiast tworzyć nowe.
źródło
plt.ion()
przedplt.show()
? Powinien wtedy być nieblokujący, ponieważ każdy wątek jest odradzany w wątku podrzędnym.matplotlib
.Odpowiedzi:
Długo szukałem rozwiązań i znalazłem tę odpowiedź .
Wygląda na to, aby dostać to, czego (i) chce, trzeba kombinacji
plt.ion()
,plt.show()
(nieblock=False
) i, co najważniejsze,plt.pause(.001)
(lub bez względu na czas chcesz). Przerwa jest potrzebna, ponieważ zdarzenia GUI zdarzyć natomiast główny kod jest snem, w tym rysunku. Możliwe, że jest to realizowane poprzez zbieranie czasu z uśpionego wątku, więc może IDE z tym mieszają - nie wiem.Oto implementacja, która działa dla mnie w Pythonie 3.5:
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()
źródło
plt.draw
następujeplt.show(block = False)
ale potem przestał działać: Rysunek nie reaguje, zamykając rozbił ipython. Moim rozwiązaniem było usunięcie każdego wystąpieniaplt.draw()
i zastąpienie goplt.pause(0.001)
. Zamiast tego,plt.show(block = False)
jakplt.draw
poprzednio, poprzedza goplt.ion()
iplt.show()
. Mam teraz,MatplotlibDeprecationWarning
ale pozwala mi wykreślić moje dane, więc jestem zadowolony z tego rozwiązania.raw_input
notinput
. Zobacz tutajProsta sztuczka, która działa dla mnie, jest następująca:
Przykład :
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()
Uwaga :
plt.show()
to ostatnia linia mojego skryptu.źródło
Możesz uniknąć blokowania wykonania, zapisując wykres do tablicy, a następnie wyświetlając tablicę w innym wątku. Oto przykład jednoczesnego generowania i wyświetlania wykresów przy użyciu pf.screen z pyformulas 0.2.8 :
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()
Wynik:
Zastrzeżenie: jestem opiekunem pyformulas.
Źródła : Matplotlib: save plot to numpy array
źródło
Wiele z tych odpowiedzi jest bardzo zawyżonych iz tego, co mogę znaleźć, odpowiedź nie jest wcale taka trudna do zrozumienia.
Możesz użyć,
plt.ion()
jeśli chcesz, ale uważam, że używanieplt.draw()
jest równie skuteczneW moim konkretnym projekcie kreślę obrazy, ale zamiast tego możesz użyć
plot()
lubscatter()
lub cokolwiek innegofigimage()
, to nie ma znaczenia.plt.figimage(image_to_show) plt.draw() plt.pause(0.001)
Lub
fig = plt.figure() ... fig.figimage(image_to_show) fig.canvas.draw() plt.pause(0.001)
Jeśli używasz rzeczywistej figury.
Użyłem @ krs013 i odpowiedzi @Default Picture, aby to zrozumiećMam
nadzieję , że to oszczędza komuś wypuszczania każdej postaci w osobnym wątku lub czytania tych powieści tylko po to, aby to zrozumieć
źródło
Drukowanie na żywo
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
jeśli ilość danych jest zbyt duża, można obniżyć szybkość aktualizacji za pomocą prostego licznika
cnt += 1 if (cnt == 10): # update plot each 10 points plt.draw() plt.pause(0.01) cnt = 0
Działka wstrzymana po zakończeniu programu
To był mój rzeczywisty problem, na który nie mogłem znaleźć satysfakcjonującej odpowiedzi, chciałem stworzyć wykres, który nie zamknął się po zakończeniu skryptu (jak MATLAB),
Jeśli się nad tym zastanowić, to po zakończeniu skryptu program zostaje zakończony i nie ma logicznego sposobu na utrzymanie wykresu w ten sposób, więc są dwie opcje
nie było to dla mnie satysfakcjonujące, więc znalazłem inne rozwiązanie poza pudełkiem
SaveToFile i View w zewnętrznej przeglądarce
W tym celu zapisywanie i przeglądanie powinno być szybkie, a przeglądarka nie powinna blokować pliku i powinna automatycznie aktualizować zawartość
Wybieranie formatu do zapisania
formaty wektorowe są małe i szybkie
Szybka i lekka przeglądarka z aktualizacją na żywo
W przypadku formatu PDF jest kilka dobrych opcji
W systemie Windows używam SumatraPDF, który jest darmowy, szybki i lekki (używa tylko 1,8 MB pamięci RAM w moim przypadku)
W systemie Linux jest kilka opcji, takich jak Evince (GNOME) i Ocular (KDE)
Przykładowy kod i wyniki
Przykładowy kod do wysyłania wykresu do pliku
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")
po pierwszym uruchomieniu otwórz plik wyjściowy w jednej z wyżej wymienionych przeglądarek i ciesz się.
Oto zrzut ekranu VSCode obok SumatraPDF, również proces jest wystarczająco szybki, aby uzyskać częstotliwość odświeżania pół-na żywo (mogę uzyskać blisko 10 Hz na mojej konfiguracji, po prostu używam
time.sleep()
między interwałami)źródło
Odpowiedź Iggy'ego była dla mnie najłatwiejsza do naśladowania, ale otrzymałem następujący błąd podczas wykonywania kolejnego
subplot
polecenia, którego nie było, gdy robiłemshow
:Aby uniknąć tego błędu, pomaga zamknąć (lub wyczyścić ) wykres po wejściu użytkownika.
Oto kod, który działał dla mnie:
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()
źródło
Pakiet drawnow w Pythonie pozwala na aktualizację wykresu w czasie rzeczywistym w sposób nieblokujący.
Działa również z kamerą internetową i OpenCV, na przykład do kreślenia miar dla każdej klatki.
Zobacz oryginalny post .
źródło
Doszedłem do wniosku, że
plt.pause(0.001)
potrzebna jest tylko komenda i nic więcej.plt.show () i plt.draw () są niepotrzebne i / lub blokują się w taki czy inny sposób. Oto kod, który rysuje i aktualizuje figurę i kontynuuje działanie. Zasadniczo plt.pause (0,001) wydaje się być najbliższym odpowiednikiem drawnow w programie Matlab.
Niestety te wykresy nie będą interaktywne (zawieszają się), z wyjątkiem wstawienia polecenia input (), ale wtedy kod się zatrzyma.
Dokumentacja polecenia plt.pause (interwał) podaje:
i to jest dokładnie to, czego chcemy. Wypróbuj ten kod:
import numpy as np from matplotlib import pyplot as plt x = np.arange(0, 51) for pow in range(10, 50): y = np.power(x, pow/10) plt.cla() # erase previous lines plt.axis([-50, 50, 0, 10000]) plt.plot(x, y) # use plt.pause() instead of the blocking plt.show() and plt.draw() # this DOES the actual plotting (plus a pause) plt.pause(0.1) # pick 0.001 or smaller if you don't want to wait # you can put your input() statement here or anything else
źródło