常见地图白化方法(一)

文摘   科学   2024-07-13 08:03   北京  

前言

地图白化是一种绘制地图的技术,它可以实现对感兴趣区域以外的数据进行遮盖或填充白色的效果,从而突出显示目标区域的特征。
地图白化的原理是利用 shapefile 文件中的多边形坐标来创建一个剪切路径,然后将这个路径应用到 matplotlib 的绘图对象上,使得只有路径内的数据可见,路径外的数据被隐藏或覆盖。
气象家园的五星上将兰溪之水说过,其实所谓的“白化”一般就两种途径:①mask数据;②mask图形

方法一 set_clip_path方法

matplotlib 官方函数示例

import numpy as np import matplotlib.cm as cm import matplotlib.pyplot as plt from matplotlib.path import Path from matplotlib.patches import PathPatch  delta = 0.025x = y = np.arange(-3.0, 3.0, delta) X, Y = np.meshgrid(x, y)   Z1 = np.exp(-X**2 - Y**2) Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) Z = (Z1 - Z2) * 2   path = Path([[0, 1], [1, 0], [0, -1],             [-1, 0], [0, 1]]) patch = PathPatch(path, facecolor ='none')    fig, ax = plt.subplots() ax.add_patch(patch)    im = ax.imshow(Z,                interpolation ='bilinear',                 cmap = cm.gray,                origin ='lower',                 extent =[-3, 3, -3, 3],                clip_path = patch,                 clip_on = True)   im.set_clip_path(patch)   fig.suptitle('matplotlib.axes.Axes.set_clip_path()function Example\n\n', fontweight ="bold")   plt.show() 

代码的目的是生成一个二维网格图,并在其中添加一个路径(path)作为剪裁(clip)区域,只显示路径内部的部分。
原图如下

fig, ax = plt.subplots() ax.imshow(Z,     interpolation ='bilinear',      cmap = cm.gray,      origin ='lower',      extent =[-3, 3, -3, 3]) plt.show() 

属于mask图片类型

读取era5数据import xarray as xrnc = xr.open_dataset('/home/mw/input/1107125177/2023110720.nc')
数据处理data= nc.z[0,2,:,:]lon=data.longitudelat=data.latitude
导入库与生成路径import cartopy.io.shapereader as shpreaderfrom cartopy.mpl.patch import geos_to_pathimport matplotlib.pyplot as pltfrom matplotlib.path import Pathimport cartopy.crs as ccrsimport cmaps# 读取shp文件shp_path = '/home/mw/input/china1656/china_map/china_map/China_Province_2022.shp'shp = shpreader.Reader(shp_path)geo_list = list(shp.geometries())proj = ccrs.PlateCarree()poly = geo_list[17]path = Path.make_compound_path(*geos_to_path(poly))
绘图部分In [16]:fig = plt.figure(figsize=(12, 8))ax = fig.add_subplot(projection=ccrs.PlateCarree())
cf = ax.contourf(lon, lat, data/98 ,levels=np.arange(520,600,4),transform=proj, cmap=cmaps.radar)cr = ax.contour(lon,lat, data/98, colors='k',levels=np.arange(520,600,4))ax.clabel(cr, inline=1, fontsize=10, fmt="%i")ax.add_geometries(shp.geometries(), proj, facecolor='none', edgecolor='k') ax.set_extent([100,120,20,40])
# 白化中国以外的区域for col in cf.collections: col.set_clip_path(path, transform=ax.transData)# 色标 cb = plt.colorbar(cf, orientation='vertical', shrink=0.8)plt.show()


这时候有不懂事的小朋友要问了,你这geo_list是什么,根本看不懂
哎呀,别急,马上给你print出来

geo_list[17]

你问我为什么知道广东省的序号是17,那当然是用geopandas看的

shp = gpd.read_file("/home/mw/input/china1656/china_map/china_map/China_Province_2022.shp")shp


省级码省类型ENG_NAMEVAR_NAMEFIRST_GIDFIRST_TYPEyeargeometry
0北京市110000直辖市BeijingBěi Jīng110000Municipality2022POLYGON ((117.38335 40.22647, 117.38557 40.224...
1天津市120000直辖市TianjinTiān Jīn120000Municipality2022POLYGON ((117.56937 40.19153, 117.56744 40.189...
2河北省130000HebeiHé Běi130000Province2022MULTIPOLYGON (((118.26945 38.98097, 118.26871 ...
3山西省140000ShanxiShān Xī140000Province2022POLYGON ((114.13714 40.73445, 114.13860 40.732...
4内蒙古自治区150000自治区NeimengguNèi Měng Gǔ150000Autonomous Region2022POLYGON ((121.49813 53.32607, 121.50116 53.321...
5辽宁省210000LiaoningLiáo Níng210000Province2022MULTIPOLYGON (((121.03521 38.87021, 121.03528 ...
6吉林省220000JilinJí Lín220000Province2022POLYGON ((123.90309 46.29744, 123.90283 46.294...
7黑龙江省230000HeilongjiangHēi Lóng Jiāng230000Province2022POLYGON ((123.40249 53.53506, 123.40471 53.535...
8上海市310000直辖市ShanghaiShàng Hǎi310000Municipality2022MULTIPOLYGON (((121.87476 31.63516, 121.87542 ...
9浙江省330000ZhejiangZhè Jiāng330000Province2022MULTIPOLYGON (((120.47933 27.15321, 120.48163 ...
10安徽省340000Anhuiān Huī340000Province2022POLYGON ((116.42485 34.65234, 116.43225 34.642...
11福建省350000FujianFú Jiàn350000Province2022MULTIPOLYGON (((117.29228 23.59563, 117.29206 ...
12江西省360000JiangxiJiāng Xī360000Province2022POLYGON ((116.68416 30.07160, 116.68576 30.070...
13山东省370000ShandongShān Dōng370000Province2022MULTIPOLYGON (((119.92414 35.62384, 119.92294 ...
14河南省410000HenanHé Nán410000Province2022MULTIPOLYGON (((111.02770 33.17911, 111.02767 ...
15湖北省420000HubeiHú Běi420000Province2022MULTIPOLYGON (((113.12740 29.43223, 113.11645 ...
16湖南省430000HunanHú Nán430000Province2022MULTIPOLYGON (((109.47771 26.84005, 109.47793 ...
17广东省440000GuangdongGuǎng Dōng440000Province2022MULTIPOLYGON (((110.59023 20.37852, 110.59232 ...
18广西壮族自治区450000自治区GuangxiGuǎng Xī450000Autonomous Region2022MULTIPOLYGON (((109.20674 20.91898, 109.20686 ...
19海南省460000HainanHǎi Nán460000Province2022MULTIPOLYGON (((112.04381 3.83812, 112.01370 3...
20重庆市500000直辖市ChongqingChóng Qìng500000Municipality2022POLYGON ((109.57960 31.72849, 109.58644 31.725...
21四川省510000SichuanSì Chuān510000Province2022POLYGON ((102.95840 34.27996, 102.95933 34.270...
22贵州省520000GuizhouGuì Zhōu520000Province2022MULTIPOLYGON (((105.09467 24.92520, 105.09458 ...
23云南省530000YunnanYún Nán530000Province2022POLYGON ((99.11276 29.21149, 99.11737 29.20723...
24西藏自治区540000自治区XizangXī Zàng540000Autonomous Region2022POLYGON ((88.38821 36.47854, 88.38945 36.47845...
25陕西省610000ShaanxiShǎn Xī610000Province2022POLYGON ((108.13454 36.57919, 108.13418 36.580...
26甘肃省620000GansuGān Sù620000Province2022POLYGON ((97.19051 42.76287, 97.23601 42.67222...
27青海省630000QinghaiQīng Hǎi630000Province2022POLYGON ((100.91694 38.17344, 100.91780 38.173...
28宁夏回族自治区640000自治区NingxiaNíng Xià Huí Zú640000Autonomous Region2022MULTIPOLYGON (((106.06218 35.43728, 106.06239 ...
29新疆维吾尔自治区650000自治区XinjiangXīn Jiāng650000Autonomous Region2022POLYGON ((87.79720 49.18060, 87.81916 49.17268...
30台湾省710000TaiwanTái Wān710000Province2022MULTIPOLYGON (((123.69793 25.92930, 123.69726 ...
31香港特别行政区810000特别行政区HongKongHong Kong810000Special District2022MULTIPOLYGON (((114.22665 22.54375, 114.22661 ...
32澳门特别行政区820000特别行政区Aomenào Mén820000Special District2022MULTIPOLYGON (((113.55346 22.21547, 113.55374 ...
33江苏省320000JiangsuJiāng Sū320000Province2022MULTIPOLYGON (((121.56617 32.22928, 121.56693 ...

这时这个方法就显示出弊端,读者的shp千变万化,没安装geopandas又对自己的shp列表不熟,则要一一排查geolist

方法二 rioxarray的rio.clip


import osimport numpy as npimport geopandas as gpdimport rioxarrayimport xarray as xrfrom shapely.geometry import mappingimport matplotlib.pyplot as plt
# 读取中国省份地图数据shp = shpreader.Reader(shp_path)shpgpd = gpd.read_file(shp_path)
# 设置数据投影data.rio.write_crs("epsg:4326", inplace=True)
# 进行裁剪并绘图cliped = data.rio.clip(shpgpd.geometry.apply(mapping), shpgpd.crs, drop=False)
fig = plt.figure(figsize=(12, 8))ax = fig.add_subplot(projection=ccrs.PlateCarree())cf = ax.contourf(lon, lat, cliped/98,levels=np.arange(520,600,4), transform=proj, cmap=cmaps.radar)cr = ax.contour(lon,lat, cliped/98,levels=np.arange(520,600,4), colors='k')ax.clabel(cr, inline=1, fontsize=10, fmt="%i")ax.add_geometries(shp.geometries(), proj, facecolor='none', edgecolor='k') ax.set_extent([100,120,20,40])cb = plt.colorbar(cf, orientation='vertical', shrink=0.8)plt.show()


以上就是比较典型的mask数据类,此类锯齿较明显

拓展:一个省怎么画:使用裁剪后的行政区json进行绘图


gd = shpgpd[shpgpd['省'] == '广东省']gd.to_file('/home/mw/project/gd.geojson', driver='GeoJSON')


# 读取中国省份地图数据js_path = '/home/mw/project/gd.geojson'gpdjs = gpd.read_file(js_path)
# 设置数据投影data.rio.write_crs("epsg:4326", inplace=True)
# 进行裁剪并绘图cliped = data.rio.clip(gpdjs.geometry.apply(mapping), gpdjs.crs, drop=False)
fig = plt.figure(figsize=(12, 8))ax = fig.add_subplot(projection=ccrs.PlateCarree())cf = ax.contourf(lon, lat, cliped/98,levels=np.arange(520,600,4), transform=proj, cmap=cmaps.radar)cr = ax.contour(lon,lat, cliped/98,levels=np.arange(520,600,4), colors='k')ax.clabel(cr, inline=1, fontsize=10, fmt="%i")ax.add_geometries(shp.geometries(), proj, facecolor='none', edgecolor='k') ax.set_extent([100,120,20,40])plt.show()

方法一参考云台书使:气象绘图加强版(三十)——白化补叙
方法二参考:rioxarray官方文档


完整文件与代码

气python风雨
主要发一些涉及大气科学的Python文章与个人学习备忘录
 最新文章