爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 19929|回复: 16

[源代码] 【Python绘图】如何用Python绘制炫酷的立体地形图

[复制链接]

新浪微博达人勋

发表于 2022-3-6 12:05:19 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
本帖最后由 clarmy 于 2022-3-6 12:10 编辑

众所周知,Python的matplotlib是一个非常全面的制图库,它不仅可以绘制图表、地图,还可以绘制3D效果图,试想一下,如果你在写论文的时候,可以将立体地形图作为底图,那逼格噌一下子就上来了,今天我就来教大家画一个带有地理坐标属性的立体地形图,啥也不说,咱先上效果图:

                               
登录/注册后可看大图
上面这张图是展示了基于matplotlib+cartopy的山地阴影图在不同光影参数下的变化效果。这个变化效果有利于我们理解matplotlib对该效果的设计理念。
在我讲解之前,我推荐大家读一下matplotlib官方文档库里的这一篇文章:Topographic hillshading,该文章已经介绍了如何单独基于matplotlib绘制山地阴影图,并给出了不同渲染参数下的渲染效果图。我当初对山地立体图的学习就是从这篇文章开始的。
本教程代码所需依赖:
  1. matplotlib
  2. cartopy>=0.19.0
  3. cnmaps
  4. netCDF4
  5. numpy
复制代码

本教程使用的DEM数据:和鲸社区数据集: CHINA_DEM
另外如果想要了解cnmaps这个包的请移步文章:如何用Python优雅地绘制中国的地图
神说:要有光
光,是三维世界最重要的东西,要绘制山地立体图,首先需要理解matplotlib中的LightSource对象,顾名思义,这个对象就是“光源”,与3D 建模里的光源是同一个东西,它的调用方法是:
  1. from matplotlib.colors import LightSource
  2. ls = LightSource(azdeg=360, altdeg=30)
复制代码

其中azdeg是方位角,altdeg是高度角,这两个参数可以确定一个光源的投射方向,进而可以知道被光源投射的物体,哪一部分应该是光,哪一部分应该是影,而光影便是实现地形立体效果的金钥匙。
在我们创建了光源以后,就需要基于该光源对地形数据生成光影对象,通常情况下,对于山地阴影,我们有两个方法可以选择,一个是hillshade,另一个是shade,其中hillshade返回的是以0-1的数字代表的光影明暗特征,你可以把它理解为一个灰度图,而shade返回的是一个RGBA数组,也就是彩图,下面我们使用shade来看一个实际的例子:
  1. import netCDF4 as nc
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. import cartopy.crs as ccrs
  5. from matplotlib.colors import LightSource
  6. from cnmaps import get_map, draw_map

  7. ds = nc.Dataset('./data/cldasgrid_dem.nc')

  8. _lon = ds.variables['LON'][:]
  9. _lat = ds.variables['LAT'][:]
  10. _dem = ds.variables['elevation'][:]

  11. lon = _lon[4032: 4662]
  12. lat = _lat[1635: 2134]

  13. dem = _dem[1635: 2134, 4032: 4662]

  14. ls = LightSource(azdeg=360, altdeg=30)

  15. rgb = ls.shade(dem[::-1], cmap=plt.cm.gist_earth, blend_mode='overlay',
  16.                vert_exag=0.5, dx=10, dy=10, fraction=1.5, vmin=-2300)

  17. fig = plt.figure(figsize=(8, 8))
  18. ax = fig.add_subplot(111, projection=ccrs.PlateCarree())

  19. img = ax.imshow(rgb, extent=(lon.min(),lon.max(),lat.min(),lat.max()), transform=ccrs.PlateCarree())

  20. draw_map(get_map('河南'), color='w', linewidth=2)

  21. ax.set_extent(get_map('河南').get_extent(buffer=0))

  22. plt.show()
复制代码



                               
登录/注册后可看大图
这样,我们的第一张立体地形图就出来了,是不是很炫酷?此外,如果你调整azdegaltdeg的值,阴影的方位就会随之改变,就像文章开头那张动图一样,它就是通过修改azdeg的值以达到光线旋转照射的效果的。

由于帖子有字数限制,阅读全文请移步:如何用Python绘制炫酷的立体地形图
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2022-3-6 12:35:49 | 显示全部楼层
密码修改失败请联系微信:mofangbao
回复

使用道具 举报

新浪微博达人勋

发表于 2022-3-6 16:33:02 | 显示全部楼层
膜拜呀!漂亮!{:eb502:}{:eb502:}
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-3-7 09:48:14 | 显示全部楼层
牛!!!!!
密码修改失败请联系微信:mofangbao
回复

使用道具 举报

新浪微博达人勋

发表于 2022-3-8 21:10:15 | 显示全部楼层
楼主请教一下,LON,LAT,DEM的范围是怎么确定的?换个区域怎么画?
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-3-9 10:27:28 | 显示全部楼层
刘哔,强强强
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-3-9 10:38:49 | 显示全部楼层
太牛逼了,谢谢楼主分享。
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-3-9 14:22:42 | 显示全部楼层
mark一下                             
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2022-3-10 09:26:46 | 显示全部楼层
phys 发表于 2022-3-8 21:10
楼主请教一下,LON,LAT,DEM的范围是怎么确定的?换个区域怎么画?

范围是读取nc文件的时候根据索引手动选择的
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2022-3-10 20:42:53 | 显示全部楼层
牛啊牛啊,最近刚好在用地形nc画图
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表