Python结合Basemap/Cartopy绘制NOAA风场流线图的问题求助
风场流线图绘制问题解决方案
Basemap 方案:解决'y must be strictly increasing'错误
问题原因
NOAA提供的纬度数据默认从北到南递减(例如从60°N到-20°S),但streamplot要求输入的y坐标必须严格递增,这是报错的核心原因。另外代码中存在几处变量名笔误(如U1应为U4,lat_ticks应为parallels等)。
修正代码
from netCDF4 import Dataset as NetCDFFile import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.basemap import Basemap fig = plt.figure(figsize=(12,9)) ax = fig.add_subplot(111) nc2 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/u850b1.nc') nc4 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/v850b1.nc') # 读取并反转纬度数组,使其从南到北递增 lat = nc2.variables['lat'][:][::-1] lon = nc2.variables['lon'][:] # 同步反转U、V数据的纬度维度,匹配新的纬度顺序 U4 = nc2.variables['uwnd'][:][:, ::-1, :] V4 = nc4.variables['vwnd'][:][:, ::-1, :] map = Basemap(projection='cyl', lon_0=0, lat_0=-20, llcrnrlon=0., llcrnrlat=-20., urcrnrlon=360., urcrnrlat=61., resolution='i', suppress_ticks=False) plt.tick_params(labelleft=False, labelbottom=False, axis='both', which='major') map.drawcoastlines() parallels = np.arange(-20., 61., 20.) meridians = np.arange(0, 360., 50.) map.drawparallels(parallels, labels=[0,0,0,0], fontsize=10, dashes=(0,1), fontweight='bold') map.drawmeridians(meridians, labels=[0,0,0,0], fontsize=10, dashes=(0,1), fontweight='bold') lons, lats = np.meshgrid(lon, lat) x, y = map(lons, lats) # 使用修正后的U4、V4数据绘制流线 map.streamplot(x, y, U4[0, :, :], V4[0, :, :], density=2) plt.show()
Cartopy 方案:解决160°E-160°W区域流线缺失问题
问题原因
设置central_longitude=180后,Cartopy投影以180°为中心,但streamplot无法自动处理0-360经度的跨180°连续数据,导致该区域流线断裂。同时代码中存在U1应为U4的笔误。
修正方案1:将经度转换为-180~180范围
把原始0-360的经度转换为-180到180,配合central_longitude=180的投影,可完整绘制所有区域流线:
from netCDF4 import Dataset as NetCDFFile import numpy as np import cartopy.crs as ccrs import matplotlib.pyplot as plt from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter nc2 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/u850b1.nc') nc4 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/v850b1.nc') lat = nc2.variables['lat'][:] # 将0-360经度转换为-180~180范围 lon = nc2.variables['lon'][:] lon[lon > 180] -= 360 U4 = nc2.variables['uwnd'][:] V4 = nc4.variables['vwnd'][:] # 保持中心经度180的投影 ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180.0)) ax.coastlines() # 设置显示范围为转换后的经度区间 ax.set_extent([-180, 180, -20, 60], crs=ccrs.PlateCarree()) # 设置刻度并格式化,显示为0-360样式 ax.set_xticks(np.arange(-180, 181, 50), crs=ccrs.PlateCarree()) ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True)) ax.set_yticks(np.arange(-20, 61, 20), crs=ccrs.PlateCarree()) ax.yaxis.set_major_formatter(LatitudeFormatter()) # 使用转换后的经度和正确的U4、V4数据绘制流线 strm = plt.streamplot(lon[::5], lat[::5], U4[0,::5,::5], V4[0,::5,::5], color='blue', density=1, arrowstyle='->', arrowsize=1, transform=ccrs.PlateCarree()) plt.show()
修正方案2:不修改经度,使用默认0°中心投影
如果不想调整经度数据,可直接使用默认PlateCarree投影(中心经度0),同样能完整绘制:
from netCDF4 import Dataset as NetCDFFile import numpy as np import cartopy.crs as ccrs import matplotlib.pyplot as plt from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter nc2 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/u850b1.nc') nc4 = NetCDFFile('E:/cycle-of-Mjo/NOAA/nc/v850b1.nc') lat = nc2.variables['lat'][:] lon = nc2.variables['lon'][:] U4 = nc2.variables['uwnd'][:] V4 = nc4.variables['vwnd'][:] # 使用默认PlateCarree投影(中心经度0) ax = plt.axes(projection=ccrs.PlateCarree()) ax.coastlines() ax.set_extent([0, 360, -20, 60], crs=ccrs.PlateCarree()) # 设置0-360的经度刻度 ax.set_xticks(np.arange(0, 360, 50), crs=ccrs.PlateCarree()) ax.xaxis.set_major_formatter(LongitudeFormatter(zero_direction_label=True)) ax.set_yticks(np.arange(-20, 61, 20), crs=ccrs.PlateCarree()) ax.yaxis.set_major_formatter(LatitudeFormatter()) strm = plt.streamplot(lon[::5], lat[::5], U4[0,::5,::5], V4[0,::5,::5], color='blue', density=1, arrowstyle='->', arrowsize=1, transform=ccrs.PlateCarree()) plt.show()
内容的提问来源于stack exchange,提问作者Sedighe
相关产品推荐
相关产品推荐

