如何用Matplotlib可视化标量2D数据?

10 投票
4 回答
21345 浏览
提问于 2025-04-16 12:35

我有一个网格(X和Y矩阵)和一些标量数据(Z矩阵),我想把这些可视化。最好是能生成一个2D图像,用颜色来表示Z值。

我查了一些资料,但没找到完全符合我需求的解决方案。

使用pyplot.imshow(Z)可以得到不错的效果,但它不支持我的X和Y矩阵,所以坐标轴显示不正确,而且处理X和Y给出的不均匀分布的点时也有问题。

使用pyplot.pcolor(X,Y,Z)可以生成带颜色的方块,颜色对应于数据在某个角落的值,这样就有点误导了数据(应该在方块的中心显示数据)。而且它还忽略了数据矩阵的两个边缘。

我相信在Matplotlib中一定有更好的方法,但文档让人很难快速了解。所以我在这里问问有没有人知道更好的办法。如果能让我更新Z矩阵来制作动画,那就更好了。

4 个回答

1

如果有人看到这篇文章是为了寻找我之前想要的内容,我把上面的例子进行了修改,使用了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

感谢大家的帮助。

2

如果你的网格是均匀分布的,你可以继续使用 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')

或者像保罗建议的那样,使用一些轮廓函数。

10

这看起来不错,但效率不高:

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()

撰写回答