Python 等效于 Matlab 的 Demcmap(高程 +/- 适当的颜色图)
Python equivalent for Matlab's Demcmap (elevation +/- appropriate colormap)
我正在寻找一种方法来为 matplotlib
.
获取适合高程的颜色图
cmap 'terrain
' 看起来不错,但颜色缩放不是基于零(即,如果比例为 0->5000m,则 0->1000m 范围可能是蓝色阴影,您假设是在海平面以下)
例如:
等效的 Matlab 函数是:
demcmap
让 matplotlib 在零高程标记周围移动地形颜色图的 greens/browns 和蓝色的最佳方法是什么?
不幸的是,matplotlib 不提供 Matlab demcmap
的功能。
python basemap
包中实际上可能有一些我不知道的内置功能。
因此,坚持使用 matplotlib 板载选项,我们可以在 Whosebug 上对 Normalize
to build a color normalization centered around a point in the middle of the colormap. This technique can be found in another question 进行子类化并适应特定需求,即设置 sealevel
(最好选择 0
) 和颜色图中的值 col_val
(范围在 0 和 1 之间),该海平面应对应于该值。在地形图的情况下,似乎0.22
,对应绿松石色,可能是一个不错的选择。
然后可以将 Normalize 实例作为参数提供给 imshow
。可以在图片的第一行下方看到生成的数字。
由于海平面周围的平滑过渡,0
周围的值显示为蓝绿色,因此很难区分陆地和海洋。
因此,我们可以稍微改变一下地形图并剪掉那些颜色,这样海岸线就更清晰可见了。这是通过map的,从0到0.17,从0.25到1,从而切掉一部分。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
class FixPointNormalize(matplotlib.colors.Normalize):
"""
Inspired by
Subclassing Normalize to obtain a colormap with a fixpoint
somewhere in the middle of the colormap.
This may be useful for a `terrain` map, to set the "sea level"
to a color in the blue/turquise range.
"""
def __init__(self, vmin=None, vmax=None, sealevel=0, col_val = 0.21875, clip=False):
# sealevel is the fix point of the colormap (in data units)
self.sealevel = sealevel
# col_val is the color value in the range [0,1] that should represent the sealevel.
self.col_val = col_val
matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
x, y = [self.vmin, self.sealevel, self.vmax], [0, self.col_val, 1]
return np.ma.masked_array(np.interp(value, x, y))
# Combine the lower and upper range of the terrain colormap with a gap in the middle
# to let the coastline appear more prominently.
# inspired by
colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 56))
colors_land = plt.cm.terrain(np.linspace(0.25, 1, 200))
# combine them and build a new colormap
colors = np.vstack((colors_undersea, colors_land))
cut_terrain_map = matplotlib.colors.LinearSegmentedColormap.from_list('cut_terrain', colors)
# invent some data (height in meters relative to sea level)
data = np.linspace(-1000,2400,15**2).reshape((15,15))
# plot example data
fig, ax = plt.subplots(nrows = 2, ncols=3, figsize=(11,6) )
plt.subplots_adjust(left=0.08, right=0.95, bottom=0.05, top=0.92, hspace = 0.28, wspace = 0.15)
plt.figtext(.5, 0.95, "Using 'terrain' and FixedPointNormalize", ha="center", size=14)
norm = FixPointNormalize(sealevel=0, vmax=3400)
im = ax[0,0].imshow(data+1000, norm=norm, cmap=plt.cm.terrain)
fig.colorbar(im, ax=ax[0,0])
norm2 = FixPointNormalize(sealevel=0, vmax=3400)
im2 = ax[0,1].imshow(data, norm=norm2, cmap=plt.cm.terrain)
fig.colorbar(im2, ax=ax[0,1])
norm3 = FixPointNormalize(sealevel=0, vmax=0)
im3 = ax[0,2].imshow(data-2400.1, norm=norm3, cmap=plt.cm.terrain)
fig.colorbar(im3, ax=ax[0,2])
plt.figtext(.5, 0.46, "Using custom cut map and FixedPointNormalize (adding hard edge between land and sea)", ha="center", size=14)
norm4 = FixPointNormalize(sealevel=0, vmax=3400)
im4 = ax[1,0].imshow(data+1000, norm=norm4, cmap=cut_terrain_map)
fig.colorbar(im4, ax=ax[1,0])
norm5 = FixPointNormalize(sealevel=0, vmax=3400)
im5 = ax[1,1].imshow(data, norm=norm5, cmap=cut_terrain_map)
cbar = fig.colorbar(im5, ax=ax[1,1])
norm6 = FixPointNormalize(sealevel=0, vmax=0)
im6 = ax[1,2].imshow(data-2400.1, norm=norm6, cmap=cut_terrain_map)
fig.colorbar(im6, ax=ax[1,2])
for i, name in enumerate(["land only", "coast line", "sea only"]):
for j in range(2):
ax[j,i].text(0.96,0.96,name, ha="right", va="top", transform=ax[j,i].transAxes, color="w" )
plt.show()
我正在寻找一种方法来为 matplotlib
.
cmap 'terrain
' 看起来不错,但颜色缩放不是基于零(即,如果比例为 0->5000m,则 0->1000m 范围可能是蓝色阴影,您假设是在海平面以下)
例如:
等效的 Matlab 函数是:
demcmap
让 matplotlib 在零高程标记周围移动地形颜色图的 greens/browns 和蓝色的最佳方法是什么?
不幸的是,matplotlib 不提供 Matlab demcmap
的功能。
python basemap
包中实际上可能有一些我不知道的内置功能。
因此,坚持使用 matplotlib 板载选项,我们可以在 Whosebug 上对 Normalize
to build a color normalization centered around a point in the middle of the colormap. This technique can be found in another question 进行子类化并适应特定需求,即设置 sealevel
(最好选择 0
) 和颜色图中的值 col_val
(范围在 0 和 1 之间),该海平面应对应于该值。在地形图的情况下,似乎0.22
,对应绿松石色,可能是一个不错的选择。
然后可以将 Normalize 实例作为参数提供给 imshow
。可以在图片的第一行下方看到生成的数字。
由于海平面周围的平滑过渡,0
周围的值显示为蓝绿色,因此很难区分陆地和海洋。
因此,我们可以稍微改变一下地形图并剪掉那些颜色,这样海岸线就更清晰可见了。这是通过map的
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
class FixPointNormalize(matplotlib.colors.Normalize):
"""
Inspired by
Subclassing Normalize to obtain a colormap with a fixpoint
somewhere in the middle of the colormap.
This may be useful for a `terrain` map, to set the "sea level"
to a color in the blue/turquise range.
"""
def __init__(self, vmin=None, vmax=None, sealevel=0, col_val = 0.21875, clip=False):
# sealevel is the fix point of the colormap (in data units)
self.sealevel = sealevel
# col_val is the color value in the range [0,1] that should represent the sealevel.
self.col_val = col_val
matplotlib.colors.Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
x, y = [self.vmin, self.sealevel, self.vmax], [0, self.col_val, 1]
return np.ma.masked_array(np.interp(value, x, y))
# Combine the lower and upper range of the terrain colormap with a gap in the middle
# to let the coastline appear more prominently.
# inspired by
colors_undersea = plt.cm.terrain(np.linspace(0, 0.17, 56))
colors_land = plt.cm.terrain(np.linspace(0.25, 1, 200))
# combine them and build a new colormap
colors = np.vstack((colors_undersea, colors_land))
cut_terrain_map = matplotlib.colors.LinearSegmentedColormap.from_list('cut_terrain', colors)
# invent some data (height in meters relative to sea level)
data = np.linspace(-1000,2400,15**2).reshape((15,15))
# plot example data
fig, ax = plt.subplots(nrows = 2, ncols=3, figsize=(11,6) )
plt.subplots_adjust(left=0.08, right=0.95, bottom=0.05, top=0.92, hspace = 0.28, wspace = 0.15)
plt.figtext(.5, 0.95, "Using 'terrain' and FixedPointNormalize", ha="center", size=14)
norm = FixPointNormalize(sealevel=0, vmax=3400)
im = ax[0,0].imshow(data+1000, norm=norm, cmap=plt.cm.terrain)
fig.colorbar(im, ax=ax[0,0])
norm2 = FixPointNormalize(sealevel=0, vmax=3400)
im2 = ax[0,1].imshow(data, norm=norm2, cmap=plt.cm.terrain)
fig.colorbar(im2, ax=ax[0,1])
norm3 = FixPointNormalize(sealevel=0, vmax=0)
im3 = ax[0,2].imshow(data-2400.1, norm=norm3, cmap=plt.cm.terrain)
fig.colorbar(im3, ax=ax[0,2])
plt.figtext(.5, 0.46, "Using custom cut map and FixedPointNormalize (adding hard edge between land and sea)", ha="center", size=14)
norm4 = FixPointNormalize(sealevel=0, vmax=3400)
im4 = ax[1,0].imshow(data+1000, norm=norm4, cmap=cut_terrain_map)
fig.colorbar(im4, ax=ax[1,0])
norm5 = FixPointNormalize(sealevel=0, vmax=3400)
im5 = ax[1,1].imshow(data, norm=norm5, cmap=cut_terrain_map)
cbar = fig.colorbar(im5, ax=ax[1,1])
norm6 = FixPointNormalize(sealevel=0, vmax=0)
im6 = ax[1,2].imshow(data-2400.1, norm=norm6, cmap=cut_terrain_map)
fig.colorbar(im6, ax=ax[1,2])
for i, name in enumerate(["land only", "coast line", "sea only"]):
for j in range(2):
ax[j,i].text(0.96,0.96,name, ha="right", va="top", transform=ax[j,i].transAxes, color="w" )
plt.show()