如何在 matplotlib 中为颜色条设置动画
How to animate the colorbar in matplotlib
我有一个动画,其中的数据范围变化很大。我想要一个 colorbar
来跟踪数据的最大值和最小值(即我不希望它被修复)。问题是如何做到这一点。
理想情况下,我希望 colorbar
在自己的轴上。
以下四种我都试过了
1。天真的方法
问题:每帧都会绘制一个新的颜色条
#!/usr/bin/env python
"""
An animated image
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax = fig.add_subplot(111)
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar = fig.colorbar(frame)
frames.append(frame.collections)
ani = animation.ArtistAnimation(fig, frames, blit=False)
plt.show()
2。添加到图像
将上面的 for 循环更改为
initFrame = ax.contourf(f(x,y))
cbar = fig.colorbar(initFrame)
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar.set_clim(vmin = vmin, vmax = vmax)
cbar.draw_all()
frames.append(frame.collections + [cbar])
问题:这引发了
AttributeError: 'Colorbar' object has no attribute 'set_visible'
3。在自己的轴上绘图
问题:colorbar
没有更新。
#!/usr/bin/env python
"""
An animated image
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax1.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar = fig.colorbar(frame, cax=ax2) # Colorbar does not update
frames.append(frame.collections)
ani = animation.ArtistAnimation(fig, frames, blit=False)
plt.show()
2 和 4 的组合
问题:colorbar
是常量。
发布了一个类似的问题 here,但看起来 OP 对固定的问题感到满意 colorbar
。
虽然我不确定如何使用 ArtistAnimation
来具体执行此操作,但使用 FuncAnimation
非常简单。如果我对您的 "naive" 版本 1 进行以下修改,它会起作用。
修改版本 1
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure()
ax = fig.add_subplot(111)
# I like to position my colorbars this way, but you don't have to
div = make_axes_locatable(ax)
cax = div.append_axes('right', '5%', '5%')
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
frames.append(curVals)
cv0 = frames[0]
cf = ax.contourf(cv0, 200)
cb = fig.colorbar(cf, cax=cax)
tx = ax.set_title('Frame 0')
def animate(i):
arr = frames[i]
vmax = np.max(arr)
vmin = np.min(arr)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
cf = ax.contourf(arr, vmax=vmax, vmin=vmin, levels=levels)
cax.cla()
fig.colorbar(cf, cax=cax)
tx.set_text('Frame {0}'.format(i))
ani = animation.FuncAnimation(fig, animate, frames=10)
plt.show()
主要区别在于我在一个函数中进行色阶计算和轮廓绘制,而不是创建艺术家列表。颜色条之所以有效,是因为您可以清除前一帧的轴并在每一帧重做。
使用 contour
或 contourf
时有必要重做,因为您不能动态更改数据。但是,由于您绘制了如此多的等高线级别并且结果看起来很平滑,我认为您最好改用 imshow
- 这意味着您实际上可以只使用同一位艺术家并更改数据,并且颜色条会更新本身自动。它也快得多!
更好的版本
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure()
ax = fig.add_subplot(111)
# I like to position my colorbars this way, but you don't have to
div = make_axes_locatable(ax)
cax = div.append_axes('right', '5%', '5%')
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
# This is now a list of arrays rather than a list of artists
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
frames.append(curVals)
cv0 = frames[0]
im = ax.imshow(cv0, origin='lower') # Here make an AxesImage rather than contour
cb = fig.colorbar(im, cax=cax)
tx = ax.set_title('Frame 0')
def animate(i):
arr = frames[i]
vmax = np.max(arr)
vmin = np.min(arr)
im.set_data(arr)
im.set_clim(vmin, vmax)
tx.set_text('Frame {0}'.format(i))
# In this version you don't have to do anything to the colorbar,
# it updates itself when the mappable it watches (im) changes
ani = animation.FuncAnimation(fig, animate, frames=10)
plt.show()
我有一个动画,其中的数据范围变化很大。我想要一个 colorbar
来跟踪数据的最大值和最小值(即我不希望它被修复)。问题是如何做到这一点。
理想情况下,我希望 colorbar
在自己的轴上。
以下四种我都试过了
1。天真的方法
问题:每帧都会绘制一个新的颜色条
#!/usr/bin/env python
"""
An animated image
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax = fig.add_subplot(111)
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar = fig.colorbar(frame)
frames.append(frame.collections)
ani = animation.ArtistAnimation(fig, frames, blit=False)
plt.show()
2。添加到图像
将上面的 for 循环更改为
initFrame = ax.contourf(f(x,y))
cbar = fig.colorbar(initFrame)
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar.set_clim(vmin = vmin, vmax = vmax)
cbar.draw_all()
frames.append(frame.collections + [cbar])
问题:这引发了
AttributeError: 'Colorbar' object has no attribute 'set_visible'
3。在自己的轴上绘图
问题:colorbar
没有更新。
#!/usr/bin/env python
"""
An animated image
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
vmax = np.max(curVals)
vmin = np.min(curVals)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
frame = ax1.contourf(curVals, vmax=vmax, vmin=vmin, levels=levels)
cbar = fig.colorbar(frame, cax=ax2) # Colorbar does not update
frames.append(frame.collections)
ani = animation.ArtistAnimation(fig, frames, blit=False)
plt.show()
2 和 4 的组合
问题:colorbar
是常量。
发布了一个类似的问题 here,但看起来 OP 对固定的问题感到满意 colorbar
。
虽然我不确定如何使用 ArtistAnimation
来具体执行此操作,但使用 FuncAnimation
非常简单。如果我对您的 "naive" 版本 1 进行以下修改,它会起作用。
修改版本 1
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure()
ax = fig.add_subplot(111)
# I like to position my colorbars this way, but you don't have to
div = make_axes_locatable(ax)
cax = div.append_axes('right', '5%', '5%')
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
frames.append(curVals)
cv0 = frames[0]
cf = ax.contourf(cv0, 200)
cb = fig.colorbar(cf, cax=cax)
tx = ax.set_title('Frame 0')
def animate(i):
arr = frames[i]
vmax = np.max(arr)
vmin = np.min(arr)
levels = np.linspace(vmin, vmax, 200, endpoint = True)
cf = ax.contourf(arr, vmax=vmax, vmin=vmin, levels=levels)
cax.cla()
fig.colorbar(cf, cax=cax)
tx.set_text('Frame {0}'.format(i))
ani = animation.FuncAnimation(fig, animate, frames=10)
plt.show()
主要区别在于我在一个函数中进行色阶计算和轮廓绘制,而不是创建艺术家列表。颜色条之所以有效,是因为您可以清除前一帧的轴并在每一帧重做。
使用 contour
或 contourf
时有必要重做,因为您不能动态更改数据。但是,由于您绘制了如此多的等高线级别并且结果看起来很平滑,我认为您最好改用 imshow
- 这意味着您实际上可以只使用同一位艺术家并更改数据,并且颜色条会更新本身自动。它也快得多!
更好的版本
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1 import make_axes_locatable
fig = plt.figure()
ax = fig.add_subplot(111)
# I like to position my colorbars this way, but you don't have to
div = make_axes_locatable(ax)
cax = div.append_axes('right', '5%', '5%')
def f(x, y):
return np.exp(x) + np.sin(y)
x = np.linspace(0, 1, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
# This is now a list of arrays rather than a list of artists
frames = []
for i in range(10):
x += 1
curVals = f(x, y)
frames.append(curVals)
cv0 = frames[0]
im = ax.imshow(cv0, origin='lower') # Here make an AxesImage rather than contour
cb = fig.colorbar(im, cax=cax)
tx = ax.set_title('Frame 0')
def animate(i):
arr = frames[i]
vmax = np.max(arr)
vmin = np.min(arr)
im.set_data(arr)
im.set_clim(vmin, vmax)
tx.set_text('Frame {0}'.format(i))
# In this version you don't have to do anything to the colorbar,
# it updates itself when the mappable it watches (im) changes
ani = animation.FuncAnimation(fig, animate, frames=10)
plt.show()