Я пытаюсь сделать анимацию точечной диаграммы, где цвета и размер точек меняются на разных этапах анимации. Для данных у меня есть два numpy ndarray со значением x и значением y:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
Теперь я хочу построить диаграмму рассеяния типа
pylab.scatter(x,y,c=data[i,:])
и создайте анимацию по индексу i
. Как мне это сделать?
python
matplotlib
Никола Вианелло
источник
источник
Ответы:
Предположим, у вас есть диаграмма рассеяния
scat = ax.scatter(...)
, тогда вы можетепоменять позиции
где
array
-N x 2
сформированный массив координат x и y.изменить размеры
где
array
- одномерный массив размеров в точках.изменить цвет
где
array
- одномерный массив значений, который будет раскрашен.Вот быстрый пример использования модуля анимации .
Это немного сложнее, чем должно быть, но это должно дать вам основу для более интересных вещей.
(Код отредактирован в апреле 2019 года для обеспечения совместимости с текущими версиями. Более старый код см. В истории изменений )
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()
Если вы работаете с OSX и используете бэкэнд OSX, вам нужно будет изменить
blit=True
наblit=False
вFuncAnimation
инициализации ниже. Бэкэнд OSX не полностью поддерживает блиттинг. Производительность пострадает, но пример должен корректно работать в OSX с отключенным копированием.Для более простого примера, который просто обновляет цвета, взгляните на следующее:
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()
источник
.set_array()
будет обновлять цвет точки ?!self.Scat.set_offsets(data[:2, :])
наself.scat.set_offsets(data[:2, :].reshape(self.numpoints, 2))
Я написал целлулоид, чтобы упростить задачу. Наверное, проще всего показать на примере:
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')
Используется
ArtistAnimation
под капотом.camera.snap
фиксирует текущее состояние фигуры, которая используется для создания кадров в анимации.Изменить: чтобы количественно оценить, сколько памяти это использует, я запустил его через 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')
Подводя итог:
источник
FuncAnimation
? Какие отличия?Вот в чем дело. Я имел обыкновение быть пользователем Qt и Matlab, и я не очень хорошо знаком с системой анимации на matplotlib.
Но у меня есть способ сделать любую анимацию, которую вы хотите, точно так же, как в Matlab. Это действительно мощно. Нет необходимости проверять ссылки на модули, и вы можете построить все, что захотите. Надеюсь, это поможет.
Основная идея - использовать событие времени внутри PyQt (я уверен, что другая система Gui на Python, такая как wxPython и TraitUi, имеет тот же внутренний механизм для ответа на событие. Но я просто не знаю, как). Каждый раз, когда вызывается событие PyQt Timer, я обновляю весь холст и перерисовываю все изображение, я знаю, что скорость и производительность могут медленно изменяться, но это не так уж и много.
Вот небольшой пример:
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_())
Вы можете настроить скорость обновления в
Я, как и вы, хочу использовать анимированный график разброса для создания анимации сортировки. Но я просто не могу найти так называемую функцию "set". Так что освежил всю канву.
Надеюсь, поможет..
источник
self.startTimer
значение ... какие-нибудь советы по этому поводу? (Да, я знаю, что это было давно ...)Почему бы не попробовать это
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()
источник