python cartopy+xarray作图

python cartopy+xarray作图

画一张以北极点为中心的极地投影的地图

主要使用的包

import os
import xarray as xr     # 读取数据
import cartopy.crs as ccrs    # 设置投影
import numpy as np
import matplotlib.pyplot as plt    
import matplotlib.path as mpath

读取数据

以1982年北半球植被秋季物候为例,数据为tiff格式

eos = xr.open_rasterio('数据路径')
eos
eos[0].where(eos[0]!=eos.rio.nodata).plot.imshow() # 简单的可视化
eos.values[eos.values==-9999] = np.nan

在这里插入图片描述
在这里插入图片描述

作图

fig = plt.figure(figsize = (6,6))
fig.suptitle('eos in nh',fontsize=20)
plt.axis('off')
ax = plt.subplot(projection = ccrs.NorthPolarStereo())  # 设置坐标系的投影

# 生成一个path作为图像边界
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)


ax.coastlines()       # 添加海岸线
ax.gridlines(linestyle='--')   # 添加经纬度网
ax.set_extent([-180, 180, 30, 90], crs=ccrs.PlateCarree())  # 设置显示范围
ax.set_boundary(circle,transform = ax.transAxes)   # 设置图像边界
cbar_kwargs ={ 'shrink':0.8} # 设置colorbar的大小

eos_s[0].plot.pcolormesh(ax=ax,transform= ccrs.PlateCarree(), 
                     robust=True,vmax=340,
                     cbar_kwargs = cbar_kwargs
                     )   
# 由于数据与坐标系的投影方式不同,需要使用 transform 参数声明数据的投影方式

在这里插入图片描述

import pandas as pd import xarray as xr from cnmaps import get_adm_maps, clip_contours_by_map, draw_maps import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER import matplotlib.colors as mcolors import matplotlib.patches as mpatches # 读取数据 ds = xr.open_dataset("Z_RADA_C_BABJ_20250302000942_P_DOR_YN_FHCR_SC_1KM_20250302_000000.nc") print(ds) sm_data = ds["CREF"] # 根据实际变量名调整 lat = ds["Lat"] lon = ds["Lon"] time_coverage=ds["time"] minu_group = ds.groupby("time.minute") for group_name, group_ds in minu_group: # 当第一个循环结束时,停止遍历 minu_group print(group_name) break group_ds list_group = list(minu_group) list_group def time_mean(a): return a.mean(dim="time") monthsst = minu_group.map(time_mean) monthsst # 常量 startLon = 98 endLon = 100.15 startLat = 24 endLat = 26 # 使用cnmaps获取保山市边界 baoshan = get_adm_maps(city="保山市", level='市') # level可选'市','县','乡' # 地图白化 fig = plt.figure(figsize=(16, 8)) ax = fig.add_subplot(111, projection=ccrs.PlateCarree()) ax.set_extent([startLon, endLon, startLat, endLat], crs=ccrs.PlateCarree()) colorlevel=[-100,-50,-25,0,25,50,100,]#气温等级 colordict=['#ff0000', '#ff9628','#ffff00','#afff00','#00beff','#800040']#颜色列表 rain_map=mcolors.ListedColormap(colordict)#产生颜色映射 norm=mcolors.BoundaryNorm(colorlevel,rain_map.N)#生成索引 # 绘制土壤湿度数据 cs1= ax.contourf(lon,lat,monthsst,levels=colorlevel,cmap=rain_map,norm=norm,transform=ccrs.PlateCarree(),extend='both') labels=['<-50','-50~-25','-25~0', '0~25','25~50','>90'] #labels=['重旱','中旱', '轻旱','无旱','渍涝'] myLegend=[mpatches.Rectangle((0, 0), 1, 2, facecolor=c) for c in colordict] ax.legend(myLegend, labels,fontsize=9,frameon=False,title='图例',ncol=1, loc='lower left', bbox_to_anchor=(0, -0.01), fancybox=True) # 画县 map_with_country = get_adm_maps(province='云南省', city="保山市", level="县") print(map_with_country) draw_maps(map_with_country, linewidth=0.8, color='#5f5f5f') # 县区 stationIds = pd.read_csv("保山市县区.csv", encoding="gbk") name = stationIds['Sta'] lon = stationIds['Lon'] lat = stationIds['Lat'] lonlat = zip(lon, lat) mapname = dict(zip(name, lonlat)) for key, value in mapname.items(): print("==================", value[0], value[1]) ax.scatter(value[0], value[1], marker='.', s=10, color="k", zorder=3) ax.text(value[0] - 0.04, value[1] + 0.01, key, fontsize=10, color="k") # 添加网格和标注 gl = ax.gridlines(draw_labels=True,linewidth=0.5, color='gray', alpha=0)#网格线颜色、宽度、 gl.xformatter = LONGITUDE_FORMATTER gl.yformatter = LATITUDE_FORMATTER gl.top_labels = False gl.right_labels = False #装饰 plt.rcParams['font.sans-serif'] = ['SimHei'] # 指定中文字体(如黑体) plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 ax.set_title("保山市3月16日土壤干旱分布图", loc="center", fontsize=14,pad=10) #def add_department_watermark(fig,text): ax.text(0.98, 0.05, "制作单位:保山市气象科技服务中心\n",ha='right', va='bottom', fontsize=8, color='black',transform=ax.transAxes) #fig.text(0.98, 0.02, "制作单位:保山市气象科技服务中心\n",ha='right', va='bottom', fontsize=8, color='black') #fig.text(0.95, 0.03,"Produced by: Energy Analytics Dept | Confidential",ha='right',fontsize=9,color='#666666',alpha=0.7) #切图 bs_map_outline = get_adm_maps(province='云南省',city="保山市", record='first', only_polygon=True) clip_contours_by_map(cs1, bs_map_outline) #map_polygon=get_adm_maps(province='云南省',city="保山市", record='first', only_polygon=True) #clip_contours_by_map(bs, bs_map_outline) #map_polygon = get_adm_maps(province='云南省',city="保山市",record='first', only_polygon=True) plt.savefig('baoshan_soil_moisture_cnmap.png', dpi=800, bbox_inches='tight') plt.show() print("工作完成.") 此代码显示TypeError: cannot directly convert an xarray.Dataset into a numpy array. Instead, create an xarray.DataArray first, either with indexing on the Dataset or by invoking the `to_array()` method.请问怎么解决
03-21
从错误提示可以看出,问题是由于尝试直接将`xarray.Dataset`转换为NumPy数组引起的。需要明确地通过索引提取单个数据变量或将Dataset转化为DataArray再处理。 以下是解决方案: ### 修改的关键点 1. **检查绘制部分的数据来源** 错误通常出现在绘图函数(例如`contourf`)中使用的数据源上。你需要确认传递给`contourf`的是一个具体的`xarray.DataArray`而不是整个`xarray.Dataset`。 2. **修正代码片段** 将`monthsst`传入到`contourf`之前,确保它是一个`xarray.DataArray`而非`xarray.Dataset`。可以使用`.to_array()`或显式选择某个变量的方式解决问题。 --- #### 修改后的关键代码段 ```python # 确保 monthsst 是 DataArray 类型,如果它是 Dataset,则需进一步指定变量名 if isinstance(monthsst, xr.Dataset): # 如果有多个变量,请替换 "CREF" 为你所需的具体变量名称 sm_data = monthsst["CREF"] else: sm_data = monthsst # 更新绘图部分 cs1 = ax.contourf( lon, lat, sm_data, levels=colorlevel, cmap=rain_map, norm=norm, transform=ccrs.PlateCarree(), extend='both' ) ``` 这里假设了你的目标变量名为"CREF",如果不是该值,请替换成对应的变量名。 --- #### 其他注意事项 如果你仍然遇到问题,建议打印出`monthsst`的内容结构以更好地理解其内部组成: ```python print(type(monthsst)) # 检查是 Dataset 还是 DataArray print(monthsst.keys()) # 查看包含哪些变量 (仅适用于 Dataset) print(monthsst.dims) # 输出维度信息 ``` 这可以帮助定位具体的问题所在并做出更精确的修改。 --- ### 示例完整修复版 结合上述说明,完整的修复版本可能会像下面这样设计: ```python # ...前面省略... # 计算时间平均值 def time_mean(a): return a.mean(dim="time") monthsst = minu_group.map(time_mean) # 验证结果是否为 DataArray 并选取正确的变量 if isinstance(monthsst, xr.Dataset): sm_data = monthsst["CREF"] # 替换 CREF 成实际变量名 else: sm_data = monthsst # 设置颜色等属性... colorlevel = [-100, -50, -25, 0, 25, 50, 100] # 气温等级 colordict = ['#ff0000', '#ff9628', '#ffff00', '#afff00', '#00beff', '#800040'] # 颜色列表 rain_map = mcolors.ListedColormap(colordict) norm = mcolors.BoundaryNorm(colorlevel, rain_map.N) # 开始作图... cs1 = ax.contourf(lon, lat, sm_data, levels=colorlevel, cmap=rain_map, norm=norm, transform=ccrs.PlateCarree(), extend='both') # 后续内容保持不变... ``` --- ### 总结 主要是对`monthsst`进行了类型判断,并保证最终送入`contourf`的数据形式是正确的单一变量数值矩阵 (`xarray.DataArray`) 而非原始多维集合 (`xarray.Dataset`)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值