Clip Sample

Demonstrate clipping gridded meteorological fields with administrative boundaries. This example overlays precipitation (filled contours), 500 hPa geopotential height (contours), and 850 hPa wind vectors, then clips the layers to selected provinces.

import easyclimate_map as eclmap
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import xarray as xr
import numpy as np
import cmaps
<easyclimate-map notice>: Maps are provided as-is. Users assume all risk. No
liability. No political or territorial claims.

Load demo dataset

Use the bundled ERA5 circulation sample to drive the plotting examples.

era5_circulation_1973062200_data = xr.open_dataset("era5_circle_1973062200.nc")
era5_circulation_1973062200_data
<xarray.Dataset> Size: 4MB
Dimensions:  (lat: 321, lon: 361)
Coordinates:
  * lat      (lat) float32 1kB -10.0 -9.75 -9.5 -9.25 ... 69.25 69.5 69.75 70.0
  * lon      (lon) float32 1kB 80.0 80.25 80.5 80.75 ... 169.2 169.5 169.8 170.0
    time     datetime64[ns] 8B ...
Data variables:
    u850     (lat, lon) float64 927kB ...
    v850     (lat, lon) float64 927kB ...
    z500     (lat, lon) float64 927kB ...
    pr       (lat, lon) float64 927kB ...


Prepare variables for plotting. - Wind vectors are thinned for clearer arrows. - Z500 and precipitation are plotted as contours and filled contours.

draw_uv850_data = era5_circulation_1973062200_data[["u850", "v850"]].thin(lon = 4, lat = 4)
draw_z500_data = era5_circulation_1973062200_data["z500"]
draw_pr_data = era5_circulation_1973062200_data["pr"]

Base map: province boundaries (line)

Load and preview the province boundary lines.

zh_provinces_line = eclmap.get_zh_CN_provinces(type = "line")
zh_provinces_line.plot()
plot core clip
<Axes: >

Base map: province boundaries (polygon)

Load and preview the province boundary polygons.

zh_provinces_polygon = eclmap.get_zh_CN_provinces(type = "polygon")
zh_provinces_polygon.plot()
plot core clip
<Axes: >

Full-domain overlay

Plot precipitation, Z500 contours, and 850 hPa winds across the region.

fig, ax = plt.subplots(
    figsize = (10, 8),
    subplot_kw={"projection": ccrs.PlateCarree(central_longitude=180)},
)

ax.set_extent([105, 125, 24, 32], crs = ccrs.PlateCarree())
ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=["bottom", "left"], alpha = 0)
ax.coastlines(color="grey", linewidths=0.5, resolution = "50m")
ax.add_geometries(
    zh_provinces_line.geometry,
    crs = ccrs.PlateCarree(),
    facecolor = "none",
    edgecolor = "grey",
    alpha = 1,
    lw = 0.5
)

draw_pr_data.plot.contourf(
    ax = ax,
    levels = np.linspace(0, 5, 21),
    cmap = cmaps.precip2_17lev,
    transform = ccrs.PlateCarree(),
    cbar_kwargs = {'location': 'bottom', 'aspect': 40, 'pad': 0.05, 'label': 'mm/h'},
    zorder = 1.2
)

draw_z500_data.plot.contour(
    ax = ax,
    levels = 41,
    colors = "k",
    transform = ccrs.PlateCarree(),
    extend='both',
    zorder = 2
)

draw_uv850_data.plot.quiver(
    x = "lon", y = "lat", u = "u850", v = "v850",
    color = "r",
    scale = 200,
    regrid_shape = 10,
    headwidth = 3.5,
    width = 0.005,
    add_guide = False,
    transform = ccrs.PlateCarree(),
    zorder = 3,
)

ax.set_title("UV850 & Z500 & Pr", loc = "left")
ax.set_title("")
ax.set_title("1973-6-22 08:00 (CST)", loc = "right")
UV850 & Z500 & Pr, 1973-6-22 08:00 (CST)
Text(1.0, 1.0, '1973-6-22 08:00 (CST)')

Filter target provinces

Select Hunan, Jiangxi, and Zhejiang for regional clipping.

gdf = zh_provinces_polygon
item_name = ['湖南省', '江西省', '浙江省']

hjz_provinces_polygon = gdf[gdf['NAME'].isin(item_name)]
hjz_provinces_polygon
AREA PERIMETER BOU2_4M_ BOU2_4M_ID ADCODE93 ADCODE99 NAME geometry
222 9.277 26.825 224 33 330000 330000 浙江省 POLYGON ((119.63211 31.13934, 119.63703 31.151...
223 0.000 0.103 225 1626 330000 330000 浙江省 POLYGON ((122.67303 30.84614, 122.66479 30.846...
224 0.000 0.052 226 1634 330000 330000 浙江省 POLYGON ((122.64085 30.81904, 122.64217 30.822...
225 0.000 0.058 227 1635 330000 330000 浙江省 POLYGON ((122.62885 30.81797, 122.62411 30.819...
226 0.000 0.023 228 1642 330000 330000 浙江省 POLYGON ((122.76 30.79333, 122.76034 30.7949, ...
... ... ... ... ... ... ... ... ...
402 0.000 0.060 404 2335 330000 330000 浙江省 POLYGON ((120.58022 27.34594, 120.5809 27.3487...
403 0.000 0.023 405 2341 330000 330000 浙江省 POLYGON ((120.56306 27.33087, 120.56315 27.328...
406 0.000 0.031 408 2349 330000 330000 浙江省 POLYGON ((120.55 27.24959, 120.5595 27.24985, ...
407 0.000 0.089 409 2356 330000 330000 浙江省 POLYGON ((120.52267 27.18469, 120.52307 27.185...
408 0.000 0.071 410 2358 330000 330000 浙江省 POLYGON ((120.46658 27.16607, 120.46805 27.167...

181 rows × 8 columns



Clip by selected provinces (union geometry)

Use the provinces polygon geometry as a clip path.

fig, ax = plt.subplots(
    figsize = (10, 8),
    subplot_kw={"projection": ccrs.PlateCarree(central_longitude=180)},
)

ax.set_extent([105, 125, 24, 32], crs = ccrs.PlateCarree())
ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=["bottom", "left"], alpha = 0)
ax.coastlines(color="grey", linewidths=0.5, resolution = "50m")
ax.add_geometries(
    zh_provinces_line.geometry,
    crs = ccrs.PlateCarree(),
    facecolor = "none",
    edgecolor = "grey",
    alpha = 1,
    lw = 0.5
)

clip = eclmap.get_geometry_path(hjz_provinces_polygon, ax)

draw_pr_data.plot.contourf(
    ax = ax,
    levels = np.linspace(0, 5, 21),
    cmap = cmaps.precip2_17lev,
    transform = ccrs.PlateCarree(),
    cbar_kwargs = {'location': 'bottom', 'aspect': 40, 'pad': 0.05, 'label': 'mm/h'},
    zorder = 1.2,
    clip_path = clip["transform_clip_path"],
)

draw_z500_data.plot.contour(
    ax = ax,
    levels = 41,
    colors = "k",
    transform = ccrs.PlateCarree(),
    extend='both',
    zorder = 2,
    clip_path = clip["transform_clip_path"],
)

draw_uv850_data.plot.quiver(
    x = "lon", y = "lat", u = "u850", v = "v850",
    color = "r",
    scale = 200,
    regrid_shape = 10,
    headwidth = 3.5,
    width = 0.005,
    add_guide = False,
    transform = ccrs.PlateCarree(),
    zorder = 3,
    clip_path = clip["transform_clip_path"],
)

ax.set_title("UV850 & Z500 & Pr (Xiang, Gan, Zhe)", loc = "left")
ax.set_title("")
ax.set_title("1973-6-22 08:00 (CST)", loc = "right")
UV850 & Z500 & Pr (Xiang, Gan, Zhe), 1973-6-22 08:00 (CST)
Text(1.0, 1.0, '1973-6-22 08:00 (CST)')

Zoomed view (without rectangle clipping)

Move extent, and compare with the same region but without applying the rectangle clip.

fig, ax = plt.subplots(
    figsize = (10, 8),
    subplot_kw={"projection": ccrs.PlateCarree(central_longitude=180)},
)

ax.set_extent([112, 125, 24, 32], crs = ccrs.PlateCarree())
ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=["bottom", "left"], alpha = 0)
ax.coastlines(color="grey", linewidths=0.5, resolution = "50m")
ax.add_geometries(
    zh_provinces_line.geometry,
    crs = ccrs.PlateCarree(),
    facecolor = "none",
    edgecolor = "grey",
    alpha = 1,
    lw = 0.5
)

clip = eclmap.get_geometry_path(hjz_provinces_polygon, ax)

draw_pr_data.plot.contourf(
    ax = ax,
    levels = np.linspace(0, 5, 21),
    cmap = cmaps.precip2_17lev,
    transform = ccrs.PlateCarree(),
    cbar_kwargs = {'location': 'bottom', 'aspect': 40, 'pad': 0.05, 'label': 'mm/h'},
    zorder = 1.2,
    clip_path = clip["transform_clip_path"],
)

draw_z500_data.plot.contour(
    ax = ax,
    levels = 41,
    colors = "k",
    transform = ccrs.PlateCarree(),
    extend='both',
    zorder = 2,
    clip_path = clip["transform_clip_path"],
)

draw_uv850_data.plot.quiver(
    x = "lon", y = "lat", u = "u850", v = "v850",
    color = "r",
    scale = 200,
    regrid_shape = 10,
    headwidth = 3.5,
    width = 0.005,
    add_guide = False,
    transform = ccrs.PlateCarree(),
    zorder = 3,
    clip_path = clip["transform_clip_path"],
)

ax.set_title("UV850 & Z500 & Pr (Without Clipped)", loc = "left")
ax.set_title("")
ax.set_title("1973-6-22 08:00 (CST)", loc = "right")
UV850 & Z500 & Pr (Without Clipped), 1973-6-22 08:00 (CST)
Text(1.0, 1.0, '1973-6-22 08:00 (CST)')

Zoomed view (rectangle clipped)

To solve this error, we need to clip the target provinces to a rectangular extent, then apply the clip path.

fig, ax = plt.subplots(
    figsize = (10, 8),
    subplot_kw={"projection": ccrs.Mercator(central_longitude=180)},
)

ax.set_extent([112, 125, 24, 32], crs = ccrs.PlateCarree())
ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=["bottom", "left"], alpha = 0)
ax.coastlines(color="grey", linewidths=0.5, resolution = "50m")
ax.add_geometries(
    zh_provinces_line.geometry,
    crs = ccrs.PlateCarree(),
    facecolor = "none",
    edgecolor = "grey",
    alpha = 1,
    lw = 0.5
)

hjz_provinces_polygon_clip = eclmap.clip_rectangle_geometry(
    hjz_provinces_polygon,
    [112, 125, 24, 32]
)
clip = eclmap.get_geometry_path(hjz_provinces_polygon_clip, ax)

draw_pr_data.plot.contourf(
    ax = ax,
    levels = np.linspace(0, 5, 21),
    cmap = cmaps.precip2_17lev,
    transform = ccrs.PlateCarree(),
    cbar_kwargs = {'location': 'bottom', 'aspect': 40, 'pad': 0.05, 'label': 'mm/h'},
    zorder = 1.2,
    clip_path = clip["transform_clip_path"],
)

draw_z500_data.plot.contour(
    ax = ax,
    levels = 41,
    colors = "k",
    transform = ccrs.PlateCarree(),
    extend='both',
    zorder = 2,
    clip_path = clip["transform_clip_path"],
)

draw_uv850_data.plot.quiver(
    x = "lon", y = "lat", u = "u850", v = "v850",
    color = "r",
    scale = 200,
    regrid_shape = 10,
    headwidth = 3.5,
    width = 0.005,
    add_guide = False,
    transform = ccrs.PlateCarree(),
    zorder = 3,
    clip_path = clip["transform_clip_path"],
)

ax.set_title("UV850 & Z500 & Pr (Clipped)", loc = "left")
ax.set_title("")
ax.set_title("1973-6-22 08:00 (CST)", loc = "right")
UV850 & Z500 & Pr (Clipped), 1973-6-22 08:00 (CST)
Text(1.0, 1.0, '1973-6-22 08:00 (CST)')

Total running time of the script: (0 minutes 22.257 seconds)