有些情况下,我们需要在二维图表中使用轮廓或颜色区域来展示三维的数据(可以设想等高线地图或温度分布图)。Matplotlib 提供了三个有用的函数来处理这项任务:plt.contour
绘制轮廓图,plt.contourf
来绘制填充区域颜色的图表以及plt.imshow
来展示图像。本节会介绍几个使用它们的例子。当然我们还是首先从将需要使用的包导入 notebook 和初始化工作开始:
import matplotlib.pyplot as plt plt.style.use('seaborn-white') import numpy as np
三维可视化函数
我们首先使用一个简单的函数 绘制一个轮廓图来进行说明,我们用来作为数组广播运算的例子:
def f(x, y): return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
轮廓图可以使用plt.contour
函数进行创建。它接收三个参数:x参数代表三维网格的平面横轴坐标,y参数代表三维网格的平面纵轴坐标,而z参数代表三维网格的高度坐标。最容易用来准备这种网格数据的是np.meshgrid
函数,可以将两个一维的数组构造成一个二维的网格:
x = np.linspace(0, 5, 50) y = np.linspace(0, 5, 40) X, Y = np.meshgrid(x, y) Z = f(X, Y)
下面我们可以绘制标准的轮廓线图表:
plt.contour(X, Y, Z, colors='black');
总代码如下:
import matplotlib.pyplot as plt plt.style.use('seaborn-white') import numpy as np def f(x, y): return np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x) x = np.linspace(0, 5, 50) y = np.linspace(0, 5, 40) X, Y = np.meshgrid(x, y) Z = f(X, Y) plt.contour(X, Y, Z, colors='black'); plt.show()
图中值得注意的是,当使用单色绘制轮廓图时,虚线代表的是负数的数值,而实线代表的是正数。而轮廓线可以通过指定cmap
参数来设置线条的色图。下例中展示了使用色图且绘制了更多的轮廓线的例子,会在整个数据范围区域内等距分布有 20 条轮廓线:
plt.contour(X, Y, Z, 20, cmap='RdGy');
上例中我们选择了RdGy
(Red-Gray的缩写)色图,这对于聚集的数据来说是一个不错的选择。Matplotlib 有大量的颜色图可供使用,你可以通过在 IPython 中对plt.cm
模块使用 TAB 自动补全方法就可以看到:
plt.cm.<TAB>
上面的图看起来比第一幅图好多了,但是线条之间的空隙还是有点让人混淆。我们可以将上面的图改为填充轮廓图来解决这个问题,使用plt.contourf()
函数(注意函数名最后有个 f,代表填充 fill),这个函数的语法基本上与plt.contour()
保持一致。
并且我们加上了plt.colorbar()
函数,这个函数会在图表边上创建一个颜色图例用以展示颜色所表示的数值区域:
有了图例,很容易可以看出黑色区域代表着“峰”,而红色区域代表这“谷”。
上图有一个缺点,那就是图中颜色的阶梯是离散的而不是连续的,这通常不是我们想要的。我们可以通过设置很高的轮廓线数量来改善,但是这会导致绘制图表的性能降低:Matplotlib 必须在每个颜色阶梯上绘制一条新的轮廓多边形。更好的办法是使用plt.imshow()
函数,它会将一个二维的网格图表转换为一张图像。
下面的例子展示了该方法:
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower', cmap='RdGy') plt.colorbar() #plt.axis(aspect='image');
然而,在使用imshow()
的时候也有一些坑:
plt.imshow()
不接受 x 和 y 网格值作为参数,因此你需要手动指定extent参数[xmin, xmax, ymin, ymax]来设置图表的数据范围。plt.imshow()
使用的是默认的图像坐标,即左上角坐标点是原点,而不是通常图表的左下角坐标点。这可以通过设置origin
参数来设置。plt.imshow()
会自动根据输入数据调整坐标轴的比例;这可以通过参数来设置,例如,plt.axis(aspect='image')
能让 x 和 y 轴的单位一致。
最后,有时可能需要将轮廓图和图像结合起来。例如,下例中我们使用了半透明的背景图像(通过alpha
参数设置透明度),然后在背景图层之上绘制了轮廓图,并带有每个轮廓的数值标签(使用plt.clabel()
函数绘制标签):
contours = plt.contour(X, Y, Z, 3, colors='black') plt.clabel(contours, inline=True, fontsize=8) plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower', cmap='RdGy', alpha=0.5) plt.colorbar();
通过组合使用plt.contour
、plt.contourf
和plt.imshow
这三个函数,基本可以满足我们绘制所有这种在二维图标上的三维数据的需求。需要了解更多函数的参数信息,参考它们的文档字符串。如果你对于使用三维图表展示这种数据感兴趣,参见[在 matplotlib 中创建三维图表]。