如何用Matplotlib可视化标量2D数据?
我有一个网格(X和Y矩阵)和一些标量数据(Z矩阵),我想把这些可视化。最好是能生成一个2D图像,用颜色来表示Z值。
我查了一些资料,但没找到完全符合我需求的解决方案。
使用pyplot.imshow(Z)可以得到不错的效果,但它不支持我的X和Y矩阵,所以坐标轴显示不正确,而且处理X和Y给出的不均匀分布的点时也有问题。
使用pyplot.pcolor(X,Y,Z)可以生成带颜色的方块,颜色对应于数据在某个角落的值,这样就有点误导了数据(应该在方块的中心显示数据)。而且它还忽略了数据矩阵的两个边缘。
我相信在Matplotlib中一定有更好的方法,但文档让人很难快速了解。所以我在这里问问有没有人知道更好的办法。如果能让我更新Z矩阵来制作动画,那就更好了。
4 个回答
如果有人看到这篇文章是为了寻找我之前想要的内容,我把上面的例子进行了修改,使用了imshow来处理一堆帧的输入,而不是实时生成和使用轮廓。我们从一个形状为(nBins, nBins, nBins)的三维图像数组开始,叫做frames
。
def animate_frames(frames):
nBins = frames.shape[0]
frame = frames[0]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
for k in range(nBins):
frame = frames[k]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
del tempCS1
fig.canvas.draw()
#time.sleep(1e-2) #unnecessary, but useful
fig.clf()
fig = plt.figure()
ax = fig.add_subplot(111)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate_frames, frames)
我还找到了一种更简单的方法来完成整个过程,虽然这种方法不够稳健:
fig = plt.figure()
for k in range(nBins):
plt.clf()
plt.imshow(frames[k],cmap=plt.cm.gray)
fig.canvas.draw()
time.sleep(1e-6) #unnecessary, but useful
请注意,这两种方法似乎只在ipython --pylab=tk
下有效,也就是backend = TkAgg
。
感谢大家的帮助。
如果你的网格是均匀分布的,你可以继续使用 pcolor
,但可以调整 X 和 Y 的位置,这样数据就能在特定的值上居中,而不是在角落上。
你也可以使用散点图,明确地在准确的 X 和 Y 点上放置一些大小的点,然后把颜色设置为 Z:
x = numpy.arange(10)
y = numpy.arange(10)
X,Y = numpy.meshgrid(x,y)
Z = numpy.arange(100).reshape((10,10))
scatter(X,Y,c=Z,marker='s',s=1500)
#I picked a marker size that basically overlapped the symbols at the edges
axis('equal')
或者:
pcolor(X+0.5,Y+0.5,Z)
axis('equal')
或者像保罗建议的那样,使用一些轮廓函数。
这看起来不错,但效率不高:
from pylab import *
origin = 'lower'
delta = 0.025
x = y = arange(-3.0, 3.01, delta)
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
nr, nc = Z.shape
CS = contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), len(x)),
ls = '-',
cmap=cm.bone,
origin=origin)
CS1 = contour(
CS,
levels = linspace(Z.min(), Z.max(), len(x)),
ls = '-',
cmap=cm.bone,
origin=origin)
show()
如果是我,我会使用scipy.interpolate把数据重新插值到一个规则的网格上,然后用imshow()来显示,并设置范围来固定坐标轴。
编辑(根据评论):
制作轮廓图的动画可以这样做,但正如我所说,上面的做法效率低下,简直是对轮廓图函数的滥用。想要高效地完成你想做的事情,最好的办法是使用SciPy。你安装了吗?
import matplotlib
matplotlib.use('TkAgg') # do this before importing pylab
import time
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
def animate():
origin = 'lower'
delta = 0.025
x = y = arange(-3.0, 3.01, delta)
X, Y = meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = 10 * (Z1 - Z2)
CS1 = ax.contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), 10),
cmap=cm.bone,
origin=origin)
for i in range(10):
tempCS1 = contourf(
X, Y, Z,
levels = linspace(Z.min(), Z.max(), 10),
cmap=cm.bone,
origin=origin)
del tempCS1
fig.canvas.draw()
time.sleep(0.1)
Z += x/10
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate)
plt.show()