2016-11-30 88 views
1

我正在寻找一种方法来为matplotlib获取适当的颜色高程图。等效于Matlab的Demcmap的Python(高程+/-正确的颜色映射)

cmap'terrain'看起来不错,但颜色标注不是基于零(即如果标尺为0-> 5000m,则0-> 1000m范围可能是蓝色阴影,您将假定为低于海平面)

例如: enter image description here

Matlab的功能相当于是: demcmap

什么是让matplotlib围绕转变地形颜色表的绿色/棕色和蓝色的最佳途径零电场标记?

+0

的matplotlib颜色表应该如何知道哪些数据值在情节属于海平面? – ImportanceOfBeingErnest

+0

@ImportanceOfBeingErnest海平面是0米,因此我说为什么要在零高程图周围移动颜色表 – mjp

回答

3

不幸的是,matplotlib不提供Matlab的功能demcmap。 python basemap包中实际上可能有一些内置功能,但我不知道。

所以,坚持matplotlib机载选项,我们可以继承Normalize的子类来建立一个以色彩地图中间点为中心的颜色标准化。这项技术可以在StackOverflow的another question中找到,并根据具体需要进行调整,即设置一个sealevel(可能最好选择为0),并将颜色地图col_val(范围在0和1之间)的值设置为该海平面应该对应的值。在地形图的情况下,似乎0.22,对应turqoise颜色,可能是一个不错的选择。
然后可以将Normalize实例作为参数提供给imshow。可以在图片的第一行看到结果数字。

由于围绕海平面的平稳过渡,0左右的值出现在turqoise颜色,使得很难区分陆地和海洋。
因此,我们可以稍微更改一下地形图并剪掉这些颜色,以便海岸线更清晰可见。这是通过地图的combining two parts完成的,范围从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 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() 

enter image description here