与Matlab的Demcmap等效的Python(高程+/-适当的颜色图) [英] Python equivalent for Matlab's Demcmap (elevation +/- appropriate colormap)
问题描述
我正在寻找一种获取matplotlib
合适的高程颜色图的方法.
I am looking for a way to get an elevation appropriate colormap for matplotlib
.
cmap'terrain
'看起来不错,但是颜色缩放比例不是基于零(即,如果缩放比例为0-> 5000m,则0-> 1000m范围可能是蓝色阴影,您可能会假设是低于海平面)
the cmap 'terrain
' looks great but the colorscaling isn't based around zero (i.e. if the scale is 0->5000m, the 0->1000m range may be shades of blue, which you would assume to be for below sea-level)
例如:
Matlab函数的等效项是:
demcmap
The Matlab function equivalent is:
demcmap
让matplotlib将地形颜色图的绿色/棕色和蓝色移动到零海拔标记附近的最佳方法是什么?
What is the best way to get matplotlib to shift a terrain colormap's greens/browns and blues around the zero elevation mark?
推荐答案
不幸的是,matplotlib不提供Matlab的demcmap
功能.
python basemap
包中实际上可能有一些内置功能,我不知道这些功能.
Unfortunaly, matplotlib does not provide the functionality of Matlab's demcmap
.
There might actually be some build-in features in the python basemap
package, of which I'm not aware.
因此,坚持使用matplotlib板载选项,我们可以将 Normalize
子类化以色图中间的一个点为中心的颜色归一化.可以在StackOverflow上的另一个问题中找到该技术,并针对特定需求进行调整,即设置一个sealevel
(最好将其选择为0
)和该海平面应对应的色图col_val
中的值(介于0和1之间).对于地形图,似乎0.22
对应于绿松石色可能是一个不错的选择.
然后可以将Normalize实例作为imshow
的参数给出.所产生的图形可以在图片的第一行下方看到.
So, sticking to matplotlib on-board options, we can subclass Normalize
to build a color normalization centered around a point in the middle of the colormap. This technique can be found in another question on StackOverflow and adapted to the specific needs, namely to set a sealevel
(which is probably best chosen as 0
) and the value in the colormap col_val
(ranging between 0 and 1) to which this sealevel should correspond. In the case of the terrain map, it seems that 0.22
, corresponding to a turqoise color, might be a good choice.
The Normalize instance can then be given as an argument to imshow
. The resulting figures can be seen down below in the first row of the picture.
由于围绕海平面的平稳过渡,0
附近的值显示为绿松石色,因此很难区分陆地和海洋.
因此,我们可以稍微改变地形图,并剪掉那些颜色,以便更好地看到海岸线.这是通过组合地图的两个部分来完成的,范围从0到0.17,从0.25到0.25. 1,然后剪掉一部分.
Due to the smooth transition around the sealevel the values around 0
appear in a turqoise color, making it hard to distinguish between land and sea.
We can therefore change the terrain map a bit and cut out those colors, such that the coastline is better visible. This is done by combining two parts of the map, ranging from 0 to 0.17 and from 0.25 to 1, and thus cutting out a part of it.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors
class FixPointNormalize(matplotlib.colors.Normalize):
"""
Inspired by https://stackoverflow.com/questions/20144529/shifted-colorbar-matplotlib
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 https://stackoverflow.com/questions/31051488/combining-two-matplotlib-colormaps
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()
这篇关于与Matlab的Demcmap等效的Python(高程+/-适当的颜色图)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!