Ich versuche, eine Animation eines Streudiagramms zu erstellen, bei der sich Farben und Größe der Punkte in verschiedenen Phasen der Animation ändern. Für Daten habe ich zwei numpy ndarray mit einem x-Wert und einem y-Wert:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Jetzt möchte ich ein Streudiagramm des Typs zeichnen
pylab.scatter(x,y,c=data[i,:])
und erstellen Sie eine Animation über dem Index i
. Wie mache ich das?
python
matplotlib
Nicola Vianello
quelle
quelle
Antworten:
Angenommen, Sie haben ein Streudiagramm
scat = ax.scatter(...)
, dann können SieÄndern Sie die Positionen
wo
array
ist eineN x 2
geformte Anordnung von x- und y-Koordinaten.Ändern Sie die Größen
Wo
array
ist ein 1D-Array von Größen in Punkten.ändere die Farbe
Dabei
array
handelt es sich um ein 1D-Array von Werten, die farblich zugeordnet werden.Hier ist ein kurzes Beispiel mit dem Animationsmodul .
Es ist etwas komplexer als es sein muss, aber dies sollte Ihnen einen Rahmen geben, um schickere Dinge zu tun.
( - Code bearbeiten 2019 April mit dem aktuellen Versionen kompatibel zu sein. Für den älteren Code siehe Revisionsgeschichte )
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()
Wenn Sie auf OSX sind und die OSX - Backend verwenden, müssen Sie ändern ,
blit=True
umblit=False
in derFuncAnimation
Initialisierung unten. Das OSX-Backend unterstützt das Blitting nicht vollständig. Die Leistung wird darunter leiden, aber das Beispiel sollte unter OSX mit deaktiviertem Blitting korrekt ausgeführt werden.Ein einfacheres Beispiel, bei dem nur die Farben aktualisiert werden, finden Sie in den folgenden Abschnitten:
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=xrange(numframes), fargs=(color_data, scat)) plt.show() def update_plot(i, data, scat): scat.set_array(data[i]) return scat, main()
quelle
.set_array()
die Punktfarbe aktualisiert wird?!self.Scat.set_offsets(data[:2, :])
aufself.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
Ich habe Zelluloid geschrieben , um dies zu vereinfachen. Es ist wahrscheinlich am einfachsten, anhand eines Beispiels zu zeigen:
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')
Es wird
ArtistAnimation
unter der Haube verwendet.camera.snap
Erfasst den aktuellen Status der Figur, mit der die Frames in der Animation erstellt werden.Bearbeiten: Um zu quantifizieren, wie viel Speicher dies verwendet, habe ich es durch memory_profiler ausgeführt .
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')
Um dies zusammenzufassen:
quelle
FuncAnimation
? Was sind die Unterschiede?Hier ist das Ding. Ich war an einen Benutzer von Qt und Matlab gewöhnt und bin mit dem Animationssystem auf der matplotlib nicht ganz vertraut.
Aber ich habe einen Weg gefunden, mit dem Sie jede Art von Animation erstellen können, die Sie möchten, genau wie in Matlab. Es ist wirklich mächtig. Sie müssen die Modulreferenzen nicht überprüfen, und Sie können alles zeichnen, was Sie möchten. Also ich hoffe es kann helfen.
Die Grundidee ist, das Zeitereignis in PyQt zu verwenden (ich bin sicher, dass andere Gui-Systeme auf Python wie wxPython und TraitUi den gleichen inneren Mechanismus haben, um eine Ereignisantwort zu erstellen. Aber ich weiß einfach nicht wie). Jedes Mal, wenn ein PyQt-Timer-Ereignis aufgerufen wird, aktualisiere ich die gesamte Leinwand und zeichne das gesamte Bild neu. Ich weiß, dass Geschwindigkeit und Leistung langsam beeinflusst werden können, aber es ist nicht so viel.
Hier ist ein kleines Beispiel dafür:
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_())
Sie können die Aktualisierungsgeschwindigkeit im einstellen
Ich bin genau wie Sie, die das animierte Streudiagramm verwenden möchten, um eine Sortieranimation zu erstellen. Aber ich kann einfach keine sogenannte "Set" -Funktion finden. Also habe ich die ganze Leinwand aufgefrischt.
Ich hoffe es hilft..
quelle
self.startTimer
Werts erhalten ... irgendwelche Tipps dazu? (Ja, ich weiß, es ist eine Weile her ...)Warum nicht versuchen?
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()
quelle