Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >​使用python绘制wrf中的土地利用类型

​使用python绘制wrf中的土地利用类型

作者头像
自学气象人
发布于 2023-06-20 08:53:08
发布于 2023-06-20 08:53:08
1.2K01
代码可运行
举报
文章被收录于专栏:自学气象人自学气象人
运行总次数:1
代码可运行

利用python中的cartopy、wrf-python等库,绘制wrf中的土地利用类型。主要使用了pcolormesh函数进行绘制,绘制效果如下:

type3

原始版本

主要参考了Python气象数据处理与绘图:绘制WRF模式模拟所用的土地利用数据来进行绘制。

具体使用的版本如下:

cartopy 0.18.0 matplotlib 3.5.1 wrf-python 1.3.3

其他库如下,一般版本也没啥大的限制,就没有一一列举了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import numpy as np
from netCDF4 import Dataset
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
import cartopy.crs as ccrs
from cartopy.io.shapereader import Reader
from cartopy.mpl.gridliner import LATITUDE_FORMATTER, LONGITUDE_FORMATTER
import shapely.geometry as sgeom
from copy import copy
from wrf import to_np, getvar,get_cartopy, cartopy_xlim, cartopy_ylim, latlon_coords
import warnings

关于地图设置方面未作改动,直接使用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def find_side(ls, side):
    """
    Given a shapely LineString which is assumed to be rectangular, return the
    line corresponding to a given side of the rectangle.
    """
    minx, miny, maxx, maxy = ls.bounds
    points = {'left': [(minx, miny), (minx, maxy)],
              'right': [(maxx, miny), (maxx, maxy)],
              'bottom': [(minx, miny), (maxx, miny)],
              'top': [(minx, maxy), (maxx, maxy)],}
    return sgeom.LineString(points[side])

def lambert_xticks(ax, ticks):
    """Draw ticks on the bottom x-axis of a Lambert Conformal projection."""
    te = lambda xy: xy[0]
    lc = lambda t, n, b: np.vstack((np.zeros(n) + t, np.linspace(b[2], b[3], n))).T
    xticks, xticklabels = _lambert_ticks(ax, ticks, 'bottom', lc, te)
    ax.xaxis.tick_bottom()
    ax.set_xticks(xticks)
    ax.set_xticklabels([ax.xaxis.get_major_formatter()(xtick) for xtick in xticklabels])

def lambert_yticks(ax, ticks):
    """Draw ricks on the left y-axis of a Lamber Conformal projection."""
    te = lambda xy: xy[1]
    lc = lambda t, n, b: np.vstack((np.linspace(b[0], b[1], n), np.zeros(n) + t)).T
    yticks, yticklabels = _lambert_ticks(ax, ticks, 'left', lc, te)
    ax.yaxis.tick_left()
    ax.set_yticks(yticks)
    ax.set_yticklabels([ax.yaxis.get_major_formatter()(ytick) for ytick in yticklabels])

def _lambert_ticks(ax, ticks, tick_location, line_constructor, tick_extractor):
    """Get the tick locations and labels for an axis of a Lambert Conformal projection."""
    outline_patch = sgeom.LineString(ax.outline_patch.get_path().vertices.tolist())
    axis = find_side(outline_patch, tick_location)
    n_steps = 30
    extent = ax.get_extent(ccrs.PlateCarree())
    _ticks = []
    for t in ticks:
        xy = line_constructor(t, n_steps, extent)
        proj_xyz = ax.projection.transform_points(ccrs.Geodetic(), xy[:, 0], xy[:, 1])
        xyt = proj_xyz[..., :2]
        ls = sgeom.LineString(xyt.tolist())
        locs = axis.intersection(ls)
        if not locs:
            tick = [None]
        else:
            tick = tick_extractor(locs.xy)
        _ticks.append(tick[0])
    # Remove ticks that aren't visible:
    ticklabels = copy(ticks)
    while True:
        try:
            index = _ticks.index(None)
        except ValueError:
            break
        _ticks.pop(index)
        ticklabels.pop(index)
    return _ticks, ticklabels

修改的部分

主要是把涉及到的土地利用类型刻度和label值单独放到了函数中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def LU_MODIS21(uniq=np.arange(1, 22)):
    inds = uniq-1
    C = np.array([
    [0,.4,0],          #  1 Evergreen Needleleaf Forest
    [0,.4,.2],         #  2 Evergreen Broadleaf Forest
    [.2,.8,.2],        #  3 Deciduous Needleleaf Forest
    [.2,.8,.4],        #  4 Deciduous Broadleaf Forest
    [.2,.6,.2],        #  5 Mixed Forests
    [.3,.7,0],         #  6 Closed Shrublands
    [.82,.41,.12],     #  7 Open Shurblands
    [.74,.71,.41],     #  8 Woody Savannas
    [1,.84,.0],        #  9 Savannas
    [0,1,0],           #  10 Grasslands
    [0,1,1],           #  11 Permanant Wetlands
    [1,1,0],           #  12 Croplands
    [1,0,0],           #  13 Urban and Built-up
    [.7,.9,.3],        #  14 Cropland/Natual Vegation Mosaic
    [1,1,1],           #  15 Snow and Ice
    [.914,.914,.7],    #  16 Barren or Sparsely Vegetated
    [.5,.7,1],         #  17 Water (like oceans)
    [.86,.08,.23],     #  18 Wooded Tundra
    [.97,.5,.31],      #  19 Mixed Tundra
    [.91,.59,.48],     #  20 Barren Tundra
    [0,0,.88]])        #  21 Lake

    cm = ListedColormap(C[inds])

    labels = ['Evergreen Needleleaf Forest',
            'Evergreen Broadleaf Forest',
            'Deciduous Needleleaf Forest',
            'Deciduous Broadleaf Forest',
            'Mixed Forests',
            'Closed Shrublands',
            'Open Shrublands',
            'Woody Savannas',
            'Savannas',
            'Grasslands',
            'Permanent Wetlands',
            'Croplands',
            'Urban and Built-Up',
            'Cropland/Natural Vegetation Mosaic',
            'Snow and Ice',
            'Barren or Sparsely Vegetated',
            'Water',
            'Wooded Tundra',
            'Mixed Tundra',
            'Barren Tundra',
            'Lake']

    return cm, np.array(labels)[inds]

def ld1(landuse):
    # type 1:
    cm, labels = LU_MODIS21()
    ticks = [x+1.5 for x in range(len(labels))]

    n_max = len(labels)
    return to_np(landuse), ticks, labels, cm, n_max

def start(file_in, shp_path):
    ncfile = Dataset(file_in)
    landuse = getvar(ncfile, 'LU_INDEX')
    lats, lons = latlon_coords(landuse)
    cart_proj = get_cartopy(landuse)

    # Create a figure
    fig = plt.figure(figsize=(12,8))

    # Set the GeoAxes to the projection used by WRF
    ax = plt.axes(projection=cart_proj)

    # Use the data extent
    ax.set_xlim(cartopy_xlim(landuse))
    ax.set_ylim(cartopy_ylim(landuse))

    # # Plot data
    landuse_new, ticks, labels, cm, n_max = ld1(landuse)

    im = ax.pcolormesh(to_np(lons), to_np(lats), landuse_new, vmin=1, vmax=n_max+1,
                    cmap=cm, alpha=0.8, transform=ccrs.PlateCarree())
    cbar = fig.colorbar(im, ax=ax)
    cbar.set_ticks(ticks)
    cbar.ax.set_yticklabels(labels)

    # Add the gridlines
    ax.gridlines(color="black", linestyle="dotted")

    # add xticks and yticks
    xticks = list(np.arange(70, 140, 10))
    yticks = list(np.arange(0, 60, 10))
    fig.canvas.draw()
    ax.xaxis.set_major_formatter(LONGITUDE_FORMATTER)
    ax.yaxis.set_major_formatter(LATITUDE_FORMATTER)
    lambert_xticks(ax, xticks)
    lambert_yticks(ax, yticks)

    # 叠加shp
    ax.add_geometries(Reader(shp_path).geometries(), ccrs.PlateCarree(), lw=1.2, facecolor='none')

    # Set the labelsize
    plt.tick_params(labelsize=12)

    # Add title
    title = 'LU_INDEX(type1)'

    pic_name = r'E:\Python使用\WRF运行\绘图\土地利用类型\图片\type1.png'
    plt.title(title, fontsize=15)
    fig.savefig(pic_name, bbox_inches='tight', dpi=600)
    plt.close()
    print('土地利用绘制完毕')

def main():
    file_in = r'E:\geo_em.d01.nc'
    shp_path = 'E:\Python使用\生成shp\中国\中国.shp'    
    start(file_in, shp_path)

if __name__ == '__main__':
    main()

绘制得到的效果如下:

type1

修改思路1

其实得到上面的效果也不错,和之前文章的效果类似。

但同时不禁让人产生一个疑问,右边的colorbar中存在21类,但实际的nc数据中是否真的存在这么多?

话不多说,输出nc数据测试一下。

将读取的landuse唯一值进行输出,即:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
print(np.unique(landuse).astype(int))

输出结果:[ 1 2 3 4 5 6 7 8 10 12 13 14 16 17 18 21]

可以发现少了9、11、15、19、20这些类,对应的具体名称可以去看用户手册,这里不再细说。

因此考虑colorbar中仅显示出现的类型,不存在的类型则不显示相应的值,新增的对应函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def ld2(landuse):
    # type 2:
    uniq = np.unique(landuse).astype(int)
    cm, label = LU_MODIS21()

    ticks = [x+0.5 for x in uniq]
    labels = [label[x-1] for x in uniq]
    n_max = len(label)
    return to_np(landuse), ticks, labels, cm, n_max

只需要将原来程序中调用的ld1(landuse)换成ld2(landuse)即可。得到如下图的效果,可以看到缺少的9、11、15、19、20已经没有显示了,这样也能直观的看到LU_INDEX文件中仅有哪些类型。

type2

修改思路2

这时候强迫症又犯了,觉得colorbar中缺少了一些对应的值,实在不好看,因此考虑在colorbar中将对应颜色删除。修改思路是将landuse中对应的值进行映射,从1到最多种类值进行排序并标号,比如上面的nc文件中缺少了5种类型,最多种类值为16,则新生成的映射应该是从1,2,3...16,其中需要将10变为9,12变为10,最终效果是为了和前面对应,统一对应颜色,方便比较。使用的具体函数如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def ld3(landuse):
    # type 3:
    uniq = np.unique(landuse).astype(int)
    cm, labels = LU_MODIS21(uniq)
    links = {val:ind+1 for ind, val in enumerate(uniq)}
    landuse_new = np.vectorize(links.get)(to_np(landuse))

    ticks = np.arange(1.5, len(labels)+1)
    n_max = len(labels)
    return landuse_new, ticks, labels, cm, n_max

使用方法还是ld1(landuse)换成ld3(landuse)。显示效果如下:

type3

小结

因为之前陆续有朋友问过我有关土地利用类型绘制的问题,所以就把自己绘制和改进的思路进行分享了。

其中还有一些可以继续改进的,包括受cartopy_xlim, cartopy_ylim限制导致四条边上的格点仅显示半个面积,还有颜色调整和优化等一系列工作。

相关py脚本和数据放到网盘上了,公众号下后台回复luindex获取下载链接。

如果大家有其他思路和改进方法的,欢迎积极投稿和分享~~

Reference

[1] [Python气象数据处理与绘图:绘制WRF模式模拟所用的土地利用数据] (https://mp.weixin.qq.com/s/EdC_Z2QoNiWkQ3gvLFvfKg)

[2] [如何优雅地用字典dict映射numpy array:map和np.vectorize] (https://blog.csdn.net/weixin_39925939/article/details/121684088)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-03-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 自学气象人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python气象绘图实例-我们一起画台风(代码+数据)
前段时间袭击中国的超强台风“利奇马”,以及这两天袭击美国的五级飓风“多利安”,让我们感受到了大自然的力量。所以,今天分享一个简单的Python实例,也算是延续前面python气象绘图系列(点击链接1;点击链接2),与大家交流如何选择合适的色标来绘制台风云顶亮温展示台风的部分特征。配色方案借鉴了GOES-16 Data[1]数据的处理方法。我们此次针对于中国区域进行一个展示,数据选取GridSat-B1 CDR(数据下载地址)[2]. A climate quality, long term dataset of global infrared window brightness temperatures. 1981-present (updated quarterly)。
MeteoAI
2019/09/05
5.3K2
Python气象绘图实例-我们一起画台风(代码+数据)
【ProPlot库】ProPlot3兰伯特投影-可添加刻度(三)
虽然 cartopy 下的 Plate Carrée 投影使用方便,但中纬度下使用 Lambert 投影能更好的呈现真实的地图。用一个正圆锥切于或割于球面,将地球面投影到圆锥面上,然后沿一母线展开成平面。下图是使用proplot绘制的最终效果:
自学气象人
2022/10/09
2K0
【ProPlot库】ProPlot3兰伯特投影-可添加刻度(三)
GPM 卫星三级产品的简单可视化
之前GPM数据写了下载教程,现在简单试试可视化,毕竟是nc格式数据(下载可选),用起来相对简单
用户11172986
2024/06/20
1660
GPM 卫星三级产品的简单可视化
Python绘制气象实用地图(附代码和测试数据)
前面的推文对于常用的Python绘图工具都有了一些介绍,在这里就不赘述了。本文主要就以下几个方面:“中国区域绘图”、“包含南海”、“兰伯特投影带经纬度标签”、“基于salem的mask方法”、“进阶中国区域mask方法”、“进阶省份mask方法”。对日常的实用需求能够在一定程度上满足。后续就Python在气象常用的统计方法(显著性检验)、合成分析、多变量叠加绘图再进行推送,敬请期待!
MeteoAI
2019/08/12
16.1K3
Python绘制气象实用地图(附代码和测试数据)
绘图|解决Cartopy Lambert投影坐标轴标签设置问题
python中有两个使用最频繁的地图绘图库:Basemap和Cartopy,两者各有优劣。由于Cartopy和matplotlib的兼容性更好,并且用户友好度更高,开始逐渐被人接受。但是Cartopy也有一些缺点,其中之一就是在设置坐标轴标签的时候对于非矩形投影无法设置标签,比如Lambert投影。
bugsuse
2020/04/21
5.1K1
绘图|解决Cartopy Lambert投影坐标轴标签设置问题
WRF domain 绘制改进
prompt: color photo of a detailed topographic map —c 10 —ar 2:3
用户11172986
2024/06/20
1780
WRF domain 绘制改进
Python | WRF任意剖面风矢量的三种投影方法及绘图
旋转法:通过旋转风向量,使其与剖面方向对齐,从而得到沿剖面和垂直于剖面的风速分量。
用户11172986
2025/01/17
1850
Python | WRF任意剖面风矢量的三种投影方法及绘图
Python可视化 | WRF模式模拟数据后处理(二)
导入模块 import numpy as np from netCDF4 import Dataset import matplotlib.pyplot as plt from matplotlib.cm import get_cmap from matplotlib.colors import from_levels_and_colors import cartopy.crs as crs import cartopy.feature as cfeature from cartopy.feature i
郭好奇同学
2021/08/26
4K0
Python可视化 | WRF模式模拟数据后处理(二)
Python兰伯特投影中国区域等值线图(含南海小地图)
自定义兰伯特投影: 原作者:“坎坷”大佬 PlateCarree (无坐标转换)作图: 代码调试作者:气象水文科研猫 注:因小编时间有限,代码未进行精简。 import numpy as np i
bugsuse
2021/01/04
7.5K1
Python兰伯特投影中国区域等值线图(含南海小地图)
利用python绘制EC数据全国降水图
Python的绘图功能非常强大,在大气和海洋常常用来绘制一些有关地理方面的图。本片主要介绍python绘制EC数据(grib格式)的的全国降水分布图。
郭好奇同学
2021/11/10
6.3K9
利用python绘制EC数据全国降水图
Python可视化 | WRF模式模拟数据后处理(一)
动画在公众号中不太好放,感兴趣的大家可以去和鲸社区上手玩儿一下。代码获取在好奇心Log公众号后台回复wrf绘图
郭好奇同学
2021/08/26
6.7K2
Python可视化 | WRF模式模拟数据后处理(一)
python可视化 | 地理桑基图的绘制方法
我回答目前常用的库包不能直接绘制这样的桑基图,我错了,应该回答是目前常用的库包不能绘制这样漂亮些的桑基图。
郭好奇同学
2021/05/28
1.8K0
python可视化 | 地理桑基图的绘制方法
气象绘图——白化杂谈
什么是白化?我在一年前也是头一次接触到这个词语,其实就是将你不需要的部分的等值线、等值线填色、风场、流场等挖去。目前气象领域流行的是花式利用地图shp文件进行操作,达到白化的目的。
自学气象人
2023/06/21
1.3K0
气象绘图——白化杂谈
python绘图 | salem一招解决所有可视化中的掩膜(Mask)问题
对于空间数据,我们感兴趣的往往是其中的某一部分,对于不需要的部分需要做一些掩膜(Mask)。 比如只关注海洋的数值变化,那么陆地上的数值对我其实是一种干扰,就要想办法掩盖掉。又比如我有全国的数据变量,但是只想研究其中某几个省份,那也需要对非相关省份进行掩盖。
气象学家
2020/09/22
12.5K57
python绘图 | salem一招解决所有可视化中的掩膜(Mask)问题
Python多子图绘制代码(共享colorbar、微调子图等)
阿巴阿巴-
2025/04/19
1360
GPM卫星 IMERG 降水产品的简单可视化
GPM数据写了下载教程,现在简单试试可视化,毕竟是nc格式数据(下载可选),用起来相对简单
用户11172986
2024/07/17
1830
GPM卫星 IMERG 降水产品的简单可视化
如何在WRF中使用2020年(最新)土地利用类型数据集?
WRF中土地利用类型最高分辨率是30s,且主要分为MODIS和USGS两种,其中MODIS数据是从2000年(有的也说是2001年)的MODIS卫星遥感数据,按照IGBP20分类标准得到的,总共有21类(含第21类—Lake),USGS数据则是1992~1993年的,总共分为24类,具体类型可以参考userguide,这些数据时间都比较久远了,如果进行最新模拟的话相差20年了,所以进行了替换。
自学气象人
2023/06/21
5.3K4
如何在WRF中使用2020年(最新)土地利用类型数据集?
风云卫星AWX格式读取与可视化
近期需要读取awx格式数据,气象家园有人提到axw有对应的库,故测试一下awx的示例脚本 并作些简单美化
用户11172986
2024/06/20
5340
风云卫星AWX格式读取与可视化
Python绘制地图专用库(Cartopy)
地图绘制 大家在绘制栅格地图的时候有可能还在使用ArcGIS进行出图,但是ArcGIS出图比较慢,而且批量出图的时候又比较麻烦。 今天给大家介绍一个Python中用于地图绘制的库,Cartopy,这个库跟basemap非常相似,不过basemap现在已经不再更新。所以大家使用Python绘制地图还是使用Cartopy比较好。 Cartopy简介 Cartopy是一个Python软件包,用于地理空间数据处理,以便生成地图和其他地理空间数据分析。 网址:https://scitools.org.uk/carto
GIS与遥感开发平台
2022/04/29
2.7K0
Python绘制地图专用库(Cartopy)
如何绘制wrfout文件的垂直速度变量
首先关于上升的有两个变量,一个是wa,官网的描述是W-component of Wind on Mass Points 单位是m/s
用户11172986
2024/06/20
4270
如何绘制wrfout文件的垂直速度变量
推荐阅读
相关推荐
Python气象绘图实例-我们一起画台风(代码+数据)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验