在此降水图上显示两个水平颜色条,导致大片空白

Displaying two horizontal colorbars on this precipitation map leading to large white spaces

我正在使用 Metpy 制作精美的降水图。我认为这更像是一个 matplotlib 问题,但我对如何在该图中添加两个水平颜色条感到困惑。总体想法是在这张地图上显示降雪和降雨率,这是我通过在一个图形上使用两个等高线填充来完成的。我想显示两个颜色条,因为我有两个单独的降雪率和降雨率。理想情况下,我希望两个颜色条水平并排。我得到的最接近的是将它们堆叠在一起,并在它们之间放置一个大 space。这是我草率的代码。

import metpy
from siphon.catalog import TDSCatalog
from datetime import datetime, timedelta
%matplotlib inline
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from metpy.units import units
import metpy.calc as mpcalc
import matplotlib.pyplot as plt
import matplotlib.colors as cls
from xarray.backends import NetCDF4DataStore
import xarray as xr
from scipy.ndimage import gaussian_filter
import numpy as np

# Set up access via NCSS
gfs_catalog = ('http://thredds.ucar.edu/thredds/catalog/grib/NCEP/GFS/'
              'Global_0p5deg/catalog.xml?dataset=grib/NCEP/GFS/Global_0p5deg/Best')
cat = TDSCatalog(gfs_catalog)
ncss = cat.datasets[0].subset()
query3 = ncss.query()
query3.accept('netcdf')
query3.variables('Pressure_reduced_to_MSL_msl', 'Precipitation_rate_surface', 'Snow_depth_surface', 'Categorical_Snow_surface')
now = datetime.utcnow()
query3.time_range(now, now + timedelta(days=4))
query3.lonlat_box(west=-140, east=-60, north=60, south=20)
data3 = ncss.get_data(query3)
ds3 = xr.open_dataset(NetCDF4DataStore(data3))

#parsing data
isSnow_var = ds3.metpy.parse_cf('Categorical_Snow_surface')
precip_var = ds3.metpy.parse_cf('Precipitation_rate_surface')
longitude = precip_var.metpy.x
latitude = precip_var.metpy.y
time_index = 11

#All the Precip Stuff
precip_inch_hour = precip_var[time_index].squeeze() *  141.73228346457 
precip2 = mpcalc.smooth_n_point(precip_inch_hour, 5, 1)

#Converting to 10:1 snow ratio
snow_precip = (precip_inch_hour * isSnow_var[time_index].squeeze()) * 10

# Plot using CartoPy and Matplotlib
mapproj = ccrs.LambertConformal(central_latitude=45., central_longitude=-100.)

# Set projection of data
data_projection = ccrs.PlateCarree()

# Grab data for plotting state boundaries
states_provinces = cfeature.NaturalEarthFeature(
       category='cultural',
       name='admin_1_states_provinces_lakes',
       scale='50m',
       facecolor='none')

# Set extent and plot map lines
fig = plt.figure(1, figsize=(25.,25.))
ax = plt.subplot(111, projection=mapproj)
ax.set_extent([-125., -70, 25., 50.], ccrs.PlateCarree())
ax.coastlines('50m', edgecolor='black', linewidth=0.75)
ax.add_feature(states_provinces, edgecolor='black', linewidth=0.5)

#colormap data
precip_colors = [
   "#bde9bf",  # 0.01 - 0.02 inches 1
   "#adddb0",  # 0.02 - 0.03 inches 2
   "#9ed0a0",  # 0.03 - 0.04 inches 3
   "#8ec491",  # 0.04 - 0.05 inches 4
   "#7fb882",  # 0.05 - 0.06 inches 5
   "#70ac74",  # 0.06 - 0.07 inches 6
   "#60a065",  # 0.07 - 0.08 inches 7
   "#519457",  # 0.08 - 0.09 inches 8
   "#418849",  # 0.09 - 0.10 inches 9
   "#307c3c",  # 0.10 - 0.12 inches 10
   "#1c712e",  # 0.12 - 0.14 inches 11
   "#f7f370",  # 0.14 - 0.16 inches 12
   "#fbdf65",  # 0.16 - 0.18 inches 13
   "#fecb5a",  # 0.18 - 0.2 inches 14
   "#ffb650",  # 0.2 - 0.3 inches 15
   "#ffa146",  # 0.3 - 0.4 inches 16
   "#ff8b3c",   # 0.4 - 0.5 inches 17
   "#ff8b3c"   # 0.5 - 0.6 inches 18
]

precip_colormap = cls.ListedColormap(precip_colors)

#Precip Rate
clev_precip =  np.concatenate((np.arange(0.01, 0.1, .01), np.arange(.1, .2, .02), np.arange(.2, .61, .1)))
norm = cls.BoundaryNorm(clev_precip, 18)
cf = ax.contourf(longitude, latitude, precip2, clev_precip, cmap=precip_colormap, norm=norm, transform=ccrs.PlateCarree())
cb = plt.colorbar(cf, ticks=clev_precip, aspect=65, orientation = 'horizontal', shrink=0.6, pad=0.01)

snow_colors = [
   "#63c9d5",  # 0.1 - 0.2 inches 1
   "#5fb4ca",  # 0.2 - 0.3 inches 2
   "#5a9fc0",  # 0.3 - 0.4 inches 3
   "#558ab5",  # 0.4 - 0.5 inches 4
   "#4e76aa",  # 0.5 - 0.6 inches 5
   "#4763a0",  # 0.6 - 0.7 inches 6
   "#3e4f95",  # 0.7 - 0.8 inches 7
   "#353c8b",  # 0.8 - 0.9 inches 8
   "#292980",  # 0.9 - 1.0 inches 9
   "#493387",  # 1.0 - 1.2 inches 10
   "#643e8e",  # 1.2 - 1.4 inches 11
   "#7c4995",  # 1.4 - 1.6 inches 12
   "#94559c",  # 1.6 - 0.18 inches 13
   "#ab61a3",  # 1.8 - 2 inches 14
   "#c36eaa",  # 2 - 3 inches 15
   "#da7bb0",  # 3 - 4 inches 16
   "#f288b7"   # 4 - 5 inches 17
]

snow_colormap = cls.ListedColormap(snow_colors)

#Snow Rate
clev_snow =  np.concatenate((np.arange(.1, 1, .1), np.arange(1, 2, .2), np.arange(2, 6, 1)))
norm2 = cls.BoundaryNorm(clev_snow, 17)
cf2 = ax.contourf(longitude, latitude, snow_precip, clev_snow, cmap=snow_colormap, norm=norm2, transform=ccrs.PlateCarree())
cb2 = plt.colorbar(cf2, ticks=clev_snow, orientation = 'horizontal', pad=0.01, shrink=0.6, aspect=65)

#Valid Time
vtime = isSnow_var.metpy.time[time_index].values

#Title Info
plt.title('MSLP (hPa) with Highs and Lows, 1000-500 hPa Thickness (m), Rain (in/hr), Snow 10:1 (in/hr)', loc='left')
plt.title(f'VALID: {vtime}', loc='right')

我尝试过子图和 gridSpec,但我一直遇到不同的障碍,在尝试这些不同的方法时遇到不同的错误。我认为这主要与我对 Metpy、Cartopy 和 Matplotlib 的入门级知识有关。感谢对此问题的任何见解和可能的解决方案。谢谢!

首先,感谢您以可重现的方式发布所有代码!

这看起来像是 subaxes 的解决方案。使用 fig.add_axes 您可以在需要的地方精确地创建子轴。

我使用了以下两个块来代替您的 cb 语句:

cax1 = fig.add_axes([0.15, 0.25, 0.3, 0.02])
cb = fig.colorbar(cf, cax=cax1, orientation = 'horizontal')

cax2 = fig.add_axes([0.55, 0.25, 0.3, 0.02])
cb2 = fig.colorbar(cf2, cax=cax2, orientation = 'horizontal')

这将创建两个并排的水平颜色条。这四个数字是左下角的位置 x 然后 y 和大小 x 然后 y,都是图形大小的比例。我没有在这台机器上工作的 metpy,所以不得不使用随机数据,但这应该不会影响你的结果:

n.b。当您创建新轴时,对 plt.<function> 的任何调用都将默认使用最后创建的轴,在本例中为 cb2。出于这个原因,您应该使用 mantplotlib 的首选 object-oriented 编程风格,因此使用 ax.set_title 而不是 plt.title

创建您的标题