在pyplot.contourf中隐藏等高线以仅保留填充

31 投票
4 回答
20092 浏览
提问于 2025-04-17 07:01

我有一个小项目,想制作地图图像,主要是在地形高度的等高线图上画出道路和其他东西。这个项目是为了规划山地自行车路线(我之前手动做过一些矢量图,效果很好,能很好地帮助可视化)。

目前,我从这里下载数字高程模型,格式是GeoTIFF:

http://www.ecologia.ufrgs.br/labgeo/arquivos/downloads/dados/SRTM/geotiff/rs.rar

然后我用GDAL和Matplotlib的contourf函数来创建图:

from osgeo import gdal
import matplotlib
import matplotlib.pyplot as plt
from pylab import cm
import numpy

f = 'rs.tif'

elev = gdal.Open(f)

a = elev.GetRasterBand(1).ReadAsArray()

w = elev.RasterXSize
h = elev.RasterYSize
print w, h

altura  = (0.35, 0.42)
largura = (0.70, 0.82)

a = a[int(h*altura[0]):int(h*altura[1]),
      int(w*largura[0]):int(w*largura[1])]


cont = plt.contourf(a, origin='upper', cmap=cm.gist_earth, levels=numpy.arange(0,1000,20))
plt.title('Altitudes - max: %d m; min: %d m' % (numpy.amax(a), numpy.amin(a)))
plt.show()

生成的效果是:

enter image description here

问题是这些等高线是“白色”的,造成了一些视觉上的干扰,这让我不太满意,因为我后面还想画道路和河流。

所以,我正在尝试修改contourf生成这些浅色线条的方式,可以通过设置参数或者修改源代码来实现,类似于这里提到的:

如何格式化Matplotlib的等高线

另外,如果有人知道用其他库更优雅地生成这样的地图的方法,我会非常感激!

谢谢阅读。

4 个回答

7

我试过的解决办法在把透明度设置为小于1的时候不管用,但我在这个解决方案里找到了答案:Matplotlib Contourf图在透明度小于1时出现不必要的轮廓

我加上了一个参数antialiased=True,问题就解决了。

7

这个问题的解决办法虽然不是真正的解决方案,更像是一个变通方法,其实很简单:只需要重复执行一次相同的 contourf 命令,这样就能神奇地消除那些多余的轮廓线。

正如提问者所说,当我们用 contourf 进行填充时,如果间隔设置得太近,就会出现这些多余的轮廓线。我们可以通过设置一个非常大的间隔数量来重现这个现象,比如:

plt.contourf(plon,plat,ssh,np.arange(-1,1.001,0.001)) # 2001 intervals

这样输出的结果是:

enter image description here

那些细细的多余轮廓线显然会影响填充的整体颜色。

如果你执行这个命令两次:

plt.contourf(plon,plat,ssh,np.arange(-1,1.001,0.001)) # Not once,
plt.contourf(plon,plat,ssh,np.arange(-1,1.001,0.001)) # but twice!

得到的结果是:

enter image description here

现在好多了。这里是最好的效果,使用了3次连续的 contourf 命令:

enter image description here

我再也看不到那些细细的轮廓线了!不过,遗憾的是,这样可能会显著减慢你的脚本运行速度,这取决于数组的大小和轮廓间隔的数量。如果使用更多的轮廓间隔,多余的轮廓线会更加明显。对我来说,通常使用50到100个轮廓间隔,然后执行 contourf 两次效果最好。

请注意,我使用的matplotlib版本不是最新的。这个问题可能在 1.1.0 版本中已经解决了。如果解决了,请告诉我。

Python 2.7.1 |EPD 7.0-2 (32-bit)| (r271:86832, Nov 29 2010, 13:52:51)
In [1]: matplotlib.__version__
Out[1]: '1.0.1'
61

我终于找到了解决这个长期存在的问题的好办法(现在在Matplotlib 3中),这个办法不需要多次调用轮廓函数或者把图像转成栅格格式。

需要注意的是,问题在提问中提到的情况只出现在保存为出版质量的图像格式,比如PDF,而在像PNG这样的低质量栅格文件中是不会出现的。

我的解决方案受到了这个回答的启发,那个回答是针对一个与颜色条相关的类似问题。结果发现,类似的解决办法也能解决轮廓图的问题,具体如下:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(123)
x, y = np.random.uniform(size=(100, 2)).T
z = np.exp(-x**2 - y**2)
levels = np.linspace(0, 1, 100)

cnt = plt.tricontourf(x, y, z, levels=levels, cmap="ocean")

# This is the fix for the white lines between contour levels
for c in cnt.collections:
    c.set_edgecolor("face")

plt.savefig("test.pdf")    

下面是修复前的轮廓图示例

这里输入图片描述

而下面是应用上述修复后的同一张图

这里输入图片描述

撰写回答