如何制作散点图动画
- 2025-01-03 08:41:00
- admin 原创
- 36
问题描述:
我正在尝试制作散点图的动画,其中点的颜色和大小在动画的不同阶段发生变化。对于数据,我有两个 numpy ndarray,分别具有 x 值和 y 值:
data.shape = (ntime, npoint)
x.shape = (npoint)
y.shape = (npoint)
现在我想绘制以下类型的散点图
pylab.scatter(x,y,c=data[i,:])
并在索引上创建动画i
。我该怎么做?
解决方案 1:
假设你有一个散点图,scat = ax.scatter(...)
那么你可以
改变位置
scat.set_offsets(array)
其中array
是N x 2
x 和 y 坐标的形状数组。
改变尺寸
scat.set_sizes(array)
其中array
是大小以点为单位的一维数组。
改变颜色
scat.set_array(array)
其中array
是将被颜色映射的值的一维数组。
下面是一个使用动画模块的简单示例。
它比实际要复杂一些,但它应该能给你一个框架来做更有趣的事情。
(代码于 2019 年 4 月编辑,以与当前版本兼容。有关旧代码,请参阅修订历史记录)
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
为。OSX 后端不完全支持位图传输。性能会受到影响,但示例应该可以在禁用位图传输的 OSX 上正确运行。blit=False
`FuncAnimation`
对于仅更新颜色的更简单示例,请看以下内容:
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()
解决方案 2:
我编写了celluloid来简化这一点。通过示例来展示可能最容易:
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')
总结一下:
创建 100 个地块使用了 1.9 MiB。
制作动画用了 2.3 MiB。
这种制作动画的方法总共使用了 4.2 MiB 的内存。
解决方案 3:
TL/DR:ax.set_...
如果您在制作散点图动画时遇到问题,您可以尝试清除每一帧的图(即ax.clear()
),然后根据需要重新绘制内容。这种方法比较慢,但当您想在小动画中更改很多内容时可能会很有用。
下面是一个演示这种“清晰”方法的例子:
import itertools
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
# set parameters
frames = 10
points = 20
np.random.seed(42)
# create data
data = np.random.rand(points, 2)
# set how the graph will change each frame
sizes = itertools.cycle([10, 50, 150])
colors = np.random.rand(frames, points)
colormaps = itertools.cycle(['Purples', 'Blues', 'Greens', 'Oranges', 'Reds'])
markers = itertools.cycle(['o', 'v', '^', 's', 'p'])
# init the figure
fig, ax = plt.subplots(figsize=(5,5))
def update(i):
# clear the axis each frame
ax.clear()
# replot things
ax.scatter(data[:, 0], data[:, 1],
s=next(sizes),
c=colors[i, :],
cmap=next(colormaps),
marker=next(markers))
# reformat things
ax.set_xlabel('world')
ax.set_ylabel('hello')
ani = animation.FuncAnimation(fig, update, frames=frames, interval=500)
ani.save('scatter.gif', writer='pillow')
我从 matplotlib 和其他来源看到的教程似乎没有使用这种方法,但我看到其他人(以及我自己)在这个网站上建议这样做。我看到了一些优点和缺点,但我很感激其他人的想法:
优点
您可以避免使用
set_...
散点图的方法(即.set_offsets()
,,.set_sizes()
...),这些方法的文档更晦涩难懂,也更不详细(尽管领先的答案会让您在这里走得很远!)。此外,不同的绘图类型有不同的方法(例如,您使用set_data
线,但不使用散点)。通过清除轴,您可以像 matplotlib 中的任何其他绘图一样确定每帧的绘制元素。更重要的是,不清楚某些属性是否
set
可用,例如标记类型(如注释中所述ax.set_...
)或颜色图。例如,由于标记和颜色图的变化,我不知道如何使用创建上述图表。但这对于来说非常基本ax.scatter()
。
缺点
它可能要慢得多;也就是说,清除并重新绘制所有内容似乎比这些
set...
方法更昂贵。因此,对于大型动画来说,这种方法可能有点痛苦。清除轴还会清除轴标签、轴限值、其他文本等内容。因此,需要包含这些格式内容
update
(否则它们将消失)。如果您希望某些内容发生变化,而其他内容保持不变,这可能会很烦人。
当然,速度是一个很大的缺点。下面是显示差异的示例。给出以下数据:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
np.random.seed(42)
frames = 40
x = np.arange(frames)
y = np.sin(x)
colors = itertools.cycle(['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'])
data = [(np.random.uniform(-1, 1, 10) + x[i],
np.random.uniform(-1, 1, 10) + y[i])
for i in range(frames)]
您可以使用set...
下列方法进行绘图:
fig, ax = plt.subplots()
s = ax.scatter([], [])
ax.set_xlim(-2, frames+2)
ax.set_ylim(min(y) - 1, max(y) + 1)
def update(i):
s.set_offsets(np.column_stack([data[i][0], data[i][1]]))
s.set_facecolor(next(colors))
ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('set.gif', writer='pillow')
或者“清除”方法:
fig, ax = plt.subplots()
def update(i):
ax.clear()
ax.scatter(data[i][0], data[i][1], c=next(colors))
ax.set_xlim(-2, frames+2)
ax.set_ylim(min(y) - 1, max(y) + 1)
ani = animation.FuncAnimation(fig, update, frames=frames, interval=100)
ani.save('clear.gif', writer='pillow')
要得到这个数字:
使用%%time
,我们可以看到清除和重新绘制花费的时间是原来的两倍多:
为了
set...
:Wall time: 1.33 s
为清楚起见:
Wall time: 2.73 s
使用frames
参数在不同规模下进行测试。对于较小的动画(较少的帧/数据),两种方法之间的时间差异无关紧要(对我来说,有时会导致我更喜欢清除方法)。但对于较大的情况,使用set_...
可以节省大量时间。
解决方案 4:
事情是这样的。我曾经是 Qt 和 Matlab 的用户,但我对 matplotlib 上的动画系统不太熟悉。
但我确实找到了一种方法,可以像在 matlab 中一样制作您想要的任何类型的动画。它真的很强大。无需检查模块引用,您就可以绘制任何您想要的东西。所以我希望它能有所帮助。
基本思想是使用 PyQt 内部的时间事件(我确信 Python 上的其他 Gui 系统如 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_())
您可以在
self.timer = self.startTimer(100)
我和你一样,想用动画散点图制作排序动画。但我就是找不到所谓的“设置”功能。所以我刷新了整个画布。
希望有帮助。
解决方案 5:
为什么不尝试一下
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()
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件