
高程数据体现了地形高低变化,可以通过读取高程数据二维数组,用imshow将高程用不同颜色表示出来绘图显示地形。
fn = 'D:/Temp/nc/etopo2_new.nc'
f = addfile(fn)
data = f['z']['25:50','72:115']
#Plot
axesm()
geoshow('country', edgecolor='k')
imshow(data, 40, cmap='MPL_terrain')
colorbar()

上图中地形高低变化很清楚,但还缺乏立体感。在二维图中体现地形立体感需要用到山体阴影,要先计算出每个格点的坡度、坡向。
首先读取高程数据,etopo2_new.nc文件中包含了全球0.33度左右分辨率的高程数据,下面的语句通过设定经纬度范围读取部分数据,并将数据的经纬度也读取出来。
fn = 'D:/Temp/nc/etopo2_new.nc'
f = addfile(fn)
data = f['z']['25:50','72:115']
data = data.astype('float')
lon = data.dimvalue(1)
lat = data.dimvalue(0) 坡度计算需要计算格点高程变化和水平距离的比值,再取反正切。x, y方向高程的变化可以用梯度函数gradient计算,格点水平距离0.33度大约为3000米(单位和高程单位保持一致),坡度用下面的代码计算,zf 是高程的放大系数,更高的zf值会带来更大的立体感。
x, y = np.gradient(data, 3000, 3000)
zf = 1. #slope zoom factor
slope = np.arctan(zf*np.sqrt(x*x + y*y)) 绘制坡度图:
axesm()
geoshow('country', edgecolor='k')
levs = arange(0.01, 0.61, 0.01)
imshow(lon, lat, slope, levs, cmap='MPL_Greys') 
高程放大系数 zf = 5 的坡度图:

坡向用 arctan2 函数计算:
aspect = np.arctan2(-x, y) 坡向图:

计算山体阴影需要设置太阳高度角和方位角:
altitude = np.deg2rad(30)
azimuth = np.deg2rad(30)
zenith = np.pi/4 - altitude
shaded = 255.0 * ((cos(zenith)* cos(slope)) +
(sin(zenith) * sin(slope) * cos(azimuth- aspect)))
shaded[shaded<0] = 0 山体阴影绘图:
levs = arange(200., 255, 1)
imshow(lon, lat, shaded, levs, cmap='MPL_Greys_r') 
叠加上带有一定透明度的高程颜色,绘制出有立体感的高程变化图:
imshow(lon, lat, data, 40, cmap='MPL_terrain', alpha=0.6, zorder=1) 
完整的代码如下:
fn = 'D:/Temp/nc/etopo2_new.nc'
f = addfile(fn)
data = f['z']['25:50','72:115']
data = data.astype('float')
lon = data.dimvalue(1)
lat = data.dimvalue(0)
x, y = np.gradient(data, 3000, 3000)
zf = 5. #slope zoom factor
slope = np.arctan(zf*np.sqrt(x*x + y*y))
aspect = np.arctan2(-x, y)
altitude = np.deg2rad(30)
azimuth = np.deg2rad(30)
zenith = np.pi/4 - altitude
shaded = 255.0 * ((cos(zenith)* cos(slope)) +
(sin(zenith) * sin(slope) * cos(azimuth- aspect)))
shaded[shaded<0] = 0
#Plot
axesm()
geoshow('country', edgecolor='k')
#imshow(lon, lat, aspect, 40, cmap='MPL_Greys')
#levs = arange(0.01, 0.61, 0.01)
#imshow(lon, lat, slope, levs, cmap='MPL_Greys')
levs = arange(200., 255, 1)
imshow(lon, lat, shaded, levs, cmap='MPL_Greys_r')
imshow(lon, lat, data, 40, cmap='MPL_terrain', alpha=0.6, zorder=1)
colorbar() 还有一种更简单的方式估算山体阴影,不用计算坡度、坡向等,效果也不错:
fn = 'D:/Temp/nc/etopo2_new.nc'
f = addfile(fn)
data = f['z']['25:50','72:115']
lon = data.dimvalue(1)
lat = data.dimvalue(0)
x, y = np.gradient(data)
shaded = x * 0.7 + y * 0.5
#Plot
axesm()
geoshow('country', edgecolor='k')
geoshow('cn_province')
levs = linspace(-100, 100, 40)
imshow(lon, lat, shaded, levs, cmap='MPL_gist_yarg_r')
imshow(lon, lat, data, 40, cmap='MPL_terrain', alpha=0.6, zorder=2)
colorbar() 