Próbuję zrobić animację wykresu punktowego, w którym kolory i rozmiar punktów zmieniają się na różnych etapach animacji. Dla danych mam dwa numpy ndarray z wartością x i wartością y:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Teraz chcę wykreślić wykres punktowy tego typu
pylab.scatter(x,y,c=data[i,:])
i utwórz animację na indeksie i
. Jak mam to zrobic?
python
matplotlib
Nicola Vianello
źródło
źródło
Odpowiedzi:
Załóżmy, że masz wykres punktowy
scat = ax.scatter(...)
, wtedy możeszzmienić pozycje
gdzie
array
jestN x 2
ukształtowaną tablicą współrzędnych x i y.zmienić rozmiary
gdzie
array
jest tablicą 1D rozmiarów w punktach.zmienić kolor
gdzie
array
jest tablicą wartości 1D, które zostaną odwzorowane kolorem.Oto krótki przykład użycia modułu animacji .
Jest nieco bardziej skomplikowany, niż powinien, ale powinien dać ci ramy do robienia bardziej wyszukanych rzeczy.
(Kod zmieniony w kwietniu 2019 r., Aby był zgodny z aktualnymi wersjami. W przypadku starszego kodu zobacz historię wersji )
import matplotlib.pyplot as plt import matplotlib.animation as animation import numpy as np class AnimatedScatter(object): """An animated scatter plot using matplotlib.animations.FuncAnimation.""" def __init__(self, numpoints=50): self.numpoints = numpoints self.stream = self.data_stream() # Setup the figure and axes... self.fig, self.ax = plt.subplots() # Then setup FuncAnimation. self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, init_func=self.setup_plot, blit=True) def setup_plot(self): """Initial drawing of the scatter plot.""" x, y, s, c = next(self.stream).T self.scat = self.ax.scatter(x, y, c=c, s=s, vmin=0, vmax=1, cmap="jet", edgecolor="k") self.ax.axis([-10, 10, -10, 10]) # For FuncAnimation's sake, we need to return the artist we'll be using # Note that it expects a sequence of artists, thus the trailing comma. return self.scat, def data_stream(self): """Generate a random walk (brownian motion). Data is scaled to produce a soft "flickering" effect.""" xy = (np.random.random((self.numpoints, 2))-0.5)*10 s, c = np.random.random((self.numpoints, 2)).T while True: xy += 0.03 * (np.random.random((self.numpoints, 2)) - 0.5) s += 0.05 * (np.random.random(self.numpoints) - 0.5) c += 0.02 * (np.random.random(self.numpoints) - 0.5) yield np.c_[xy[:,0], xy[:,1], s, c] def update(self, i): """Update the scatter plot.""" data = next(self.stream) # Set x and y data... self.scat.set_offsets(data[:, :2]) # Set sizes... self.scat.set_sizes(300 * abs(data[:, 2])**1.5 + 100) # Set colors.. self.scat.set_array(data[:, 3]) # We need to return the updated artist for FuncAnimation to draw.. # Note that it expects a sequence of artists, thus the trailing comma. return self.scat, if __name__ == '__main__': a = AnimatedScatter() plt.show()
Jeśli jesteś na OSX i korzystania z zaplecza OSX, trzeba zmienić
blit=True
, abyblit=False
wFuncAnimation
inicjalizacji poniżej. Backend OSX nie obsługuje w pełni blittingu. Wydajność ucierpi, ale przykład powinien działać poprawnie na OSX z wyłączonym blittingiem.Aby uzyskać prostszy przykład, który po prostu aktualizuje kolory, spójrz na następujące:
import matplotlib.pyplot as plt import numpy as np import matplotlib.animation as animation def main(): numframes = 100 numpoints = 10 color_data = np.random.random((numframes, numpoints)) x, y, c = np.random.random((3, numpoints)) fig = plt.figure() scat = plt.scatter(x, y, c=c, s=100) ani = animation.FuncAnimation(fig, update_plot, frames=range(numframes), fargs=(color_data, scat)) plt.show() def update_plot(i, data, scat): scat.set_array(data[i]) return scat, main()
źródło
.set_array()
zmieni kolor kropek ?!self.Scat.set_offsets(data[:2, :])
naself.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
Napisałem celuloid, żeby to ułatwić. Prawdopodobnie najłatwiej to pokazać na przykładzie:
import matplotlib.pyplot as plt from matplotlib import cm import numpy as np from celluloid import Camera numpoints = 10 points = np.random.random((2, numpoints)) colors = cm.rainbow(np.linspace(0, 1, numpoints)) camera = Camera(plt.figure()) for _ in range(100): points += 0.1 * (np.random.random((2, numpoints)) - .5) plt.scatter(*points, c=colors, s=100) camera.snap() anim = camera.animate(blit=True) anim.save('scatter.mp4')
Używa
ArtistAnimation
pod maską.camera.snap
przechwytuje bieżący stan figury, która jest używana do tworzenia klatek w animacji.Edycja: Aby oszacować, ile pamięci to wykorzystuje, przepuściłem go przez memory_profiler .
Line # Mem usage Increment Line Contents ================================================ 11 65.2 MiB 65.2 MiB @profile 12 def main(): 13 65.2 MiB 0.0 MiB numpoints = 10 14 65.2 MiB 0.0 MiB points = np.random.random((2, numpoints)) 15 65.2 MiB 0.1 MiB colors = cm.rainbow(np.linspace(0, 1, numpoints)) 16 65.9 MiB 0.6 MiB fig = plt.figure() 17 65.9 MiB 0.0 MiB camera = Camera(fig) 18 67.8 MiB 0.0 MiB for _ in range(100): 19 67.8 MiB 0.0 MiB points += 0.1 * (np.random.random((2, numpoints)) - .5) 20 67.8 MiB 1.9 MiB plt.scatter(*points, c=colors, s=100) 21 67.8 MiB 0.0 MiB camera.snap() 22 70.1 MiB 2.3 MiB anim = camera.animate(blit=True) 23 72.1 MiB 1.9 MiB anim.save('scatter.mp4')
Podsumowując:
źródło
FuncAnimation
? Jakie są różnice?Oto rzecz. Kiedyś korzystałem z Qt i Matlaba i nie znam systemu animacji w matplotlib.
Ale znalazłem sposób, aby stworzyć dowolną animację, tak jak w Matlabie. Jest naprawdę potężny. Nie musisz sprawdzać odniesień do modułów i możesz nanieść wszystko, co chcesz. Mam więc nadzieję, że to pomoże.
Podstawowym pomysłem jest użycie zdarzenia czasowego wewnątrz PyQt (jestem pewien, że inny system Gui w Pythonie, taki jak wxPython i TraitUi, ma ten sam wewnętrzny mechanizm do reagowania na zdarzenie. Ale po prostu nie wiem jak). Za każdym razem, gdy wywoływane jest zdarzenie Timer PyQt, odświeżam całe płótno i przerysowuję cały obraz, wiem, że może to powoli wpływać na szybkość i wydajność, ale nie jest to aż tak dużo.
Oto mały przykład:
import sys from PyQt4 import QtGui from matplotlib.figure import Figure from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas import numpy as np class Monitor(FigureCanvas): def __init__(self): self.fig = Figure() self.ax = self.fig.add_subplot(111) FigureCanvas.__init__(self, self.fig) self.x = np.linspace(0,5*np.pi,400) self.p = 0.0 self.y = np.sin(self.x+self.p) self.line = self.ax.scatter(self.x,self.y) self.fig.canvas.draw() self.timer = self.startTimer(100) def timerEvent(self, evt): # update the height of the bars, one liner is easier self.p += 0.1 self.y = np.sin(self.x+self.p) self.ax.cla() self.line = self.ax.scatter(self.x,self.y) self.fig.canvas.draw() if __name__ == "__main__": app = QtGui.QApplication(sys.argv) w = Monitor() w.setWindowTitle("Convergence") w.show() sys.exit(app.exec_())
Możesz dostosować prędkość odświeżania w
Jestem jak ty, który chce użyć animowanego wykresu punktowego, aby wykonać animację sortowania. Ale po prostu nie mogę znaleźć tak zwanej funkcji „ustaw”. Więc odświeżyłem całe płótno.
Mam nadzieję, że to pomoże..
źródło
self.startTimer
wartość ... jakieś wskazówki na ten temat? (Tak, wiem, że minęło trochę czasu ...)Dlaczego nie spróbować tego
import numpy as np import matplotlib.pyplot as plt x=np.random.random() y=np.random.random() fig, ax = plt.subplots() ax.scatter(x,y,color='teal') ax.scatter(y,x,color='crimson') ax.set_xlim([0,1]) ax.set_ylim([0,1]) for i in np.arange(50): x=np.random.random() y=np.random.random() bha=ax.scatter(x,y) plt.draw() plt.pause(0.5) bha.remove() plt.show()
źródło