# How to Use Herbie's Xarray Accessor for Enhanced Meteorological Data Analysis

> Learn how to use Herbie's xarray accessor for advanced meteorological data analysis. Improve your workflow with coordinate normalization wind calculations spatial subsetting and domain geometry extraction.

- Repository: [Brian Blaylock/herbie](https://github.com/blaylockbk/herbie)
- Tags: how-to-guide
- Published: 2026-02-26

---

**Herbie's xarray accessor (`.herbie`) extends xarray Dataset objects with meteorology-specific methods for coordinate normalization, wind calculations, spatial subsetting, and domain geometry extraction, all accessible via `ds.herbie.method()`.**

The Herbie library simplifies downloading and reading GRIB2 weather model data, but its true analytical power emerges through the custom xarray accessor registered in [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py). When you open data via `H.xarray()`, the resulting Dataset automatically gains the `.herbie` namespace, providing a consistent API for common meteorological tasks without additional imports.

## What Is Herbie's Xarray Accessor?

Herbie's accessor is registered using `xr.register_dataset_accessor("herbie")` at line 95 of [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py). This decorator attaches the `HerbieAccessor` class to every xarray Dataset created through Herbie's interface.

The accessor acts as a thin wrapper around reusable utilities and external libraries like MetPy, Cartopy, and Shapely. It uses `@functools.cached_property` for expensive calculations—such as coordinate reference system (CRS) creation—ensuring computational work is performed only once per dataset.

## Core Methods for Coordinate and Spatial Analysis

### Normalizing Longitudes with `to_180` and `to_360`

Meteorological datasets often use longitude ranges of either [-180, 180] or [0, 360]. Herbie's accessor provides methods to re-wrap coordinates without manual indexing:

- **`ds.herbie.to_180()`** — Re-wraps longitudes into the range [-180, 180]
- **`ds.herbie.to_360()`** — Re-wraps longitudes into the range [0, 360]

These methods are implemented in [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py) at lines 112-122 and handle the modular arithmetic required to shift coordinate values while preserving dataset integrity.

### Calculating Grid Centers with `center`

The `center` property returns the geographic center of the grid as a tuple of `(longitude, latitude)`. It lazily computes the mean of the `latitude` and `longitude` coordinates and caches the result:

```python
lon_center, lat_center = ds.herbie.center

```

This is particularly useful when determining the map projection center or annotating spatial statistics. The implementation resides at lines 103-110 of [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py).

### Extracting Domain Boundaries with `polygon`

The `polygon` property generates two Shapely polygons describing the domain boundary: one in latitude/longitude coordinates and another in the dataset's native projected coordinates. This is essential for spatial subsetting and domain visualization:

```python
proj_poly, geo_poly = ds.herbie.polygon

```

The method uses the accessor's `crs` property to perform coordinate transformations and is implemented at lines 156-198 of [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py).

## Meteorological Calculations and Wind Analysis

### Computing Wind Speed and Direction with `with_wind`

The `with_wind()` method calculates wind speed and direction from available `u*` and `v*` wind components. It adds new variables with CF-style attributes, handling standard height levels including 10 m, 80 m, 100 m, and surface:

```python
ds_with_wind = ds.herbie.with_wind()

# Access new variables: si10, wdir10, si80, wdir80, etc.

```

The method automatically detects available wind components and applies the appropriate calculations. Implementation details are found at lines 200-267 of [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py), with helper functions in [`src/herbie/toolbox/wind.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/toolbox/wind.py).

### Cartopy CRS Integration via `crs`

The `crs` property builds a Cartopy coordinate reference system from CF metadata embedded in GRIB2 files. It lazily parses the dataset with MetPy (`ds.metpy.parse_cf`) and converts the resulting CRS to a Cartopy object:

```python
cartopy_crs = ds.herbie.crs

# Use directly with cartopy: ax = plt.axes(projection=cartopy_crs)

```

This property is cached to avoid repeated MetPy parsing overhead and is implemented at lines 124-154 of [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py).

## Spatial Subsetting and Point Extraction

### Nearest Neighbor and Weighted Interpolation with `pick_points`

The `pick_points()` method provides advanced spatial extraction capabilities, delegating to the `GridPointPicker` class in [`src/herbie/pick_points.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/pick_points.py). It supports both nearest-neighbor and distance-weighted interpolation:

```python
import pandas as pd

stations = pd.DataFrame({
    "latitude": [40.0, 29.5, 42.3],
    "longitude": [-100.0, -105.0, -98.4],
    "stid": ["AA", "BB", "CC"]
})

# Nearest neighbor extraction

ds_points = ds.herbie.pick_points(stations, method="nearest")

# Weighted interpolation (k=4 by default)

ds_weighted = ds.herbie.pick_points(stations, method="weighted")

```

The method uses `sklearn.neighbors.BallTree` for efficient spatial indexing and can cache the index on disk using the default Herbie cache directory (`herbie.config["default"]["save_dir"]`). This dramatically speeds up repeated extractions on the same model grid.

### Legacy Support with `nearest_points`

For backward compatibility, the accessor maintains a `nearest_points()` wrapper that calls the older `herbie.nearest_points` module. New code should prefer `pick_points()` for its enhanced performance and flexibility.

## Practical Implementation Examples

The following workflow demonstrates loading HRRR model data and applying multiple accessor methods for comprehensive analysis:

```python
import pandas as pd
import xarray as xr
from herbie import Herbie

# Load a GRIB2 dataset via Herbie

H = Herbie("2022-12-13 12:00", model="hrrr", product="sfc")
ds = H.xarray("TMP:2 m")  # Returns xarray.Dataset with .herbie accessor

# Normalize longitudes to [-180, 180] range

ds = ds.herbie.to_180()

# Compute wind speed and direction from u/v components

ds = ds.herbie.with_wind()

# Extract domain center for map annotations

lon_center, lat_center = ds.herbie.center

# Generate domain boundary polygons for spatial masking

proj_poly, geo_poly = ds.herbie.polygon

# Extract values at specific station locations

stations = pd.DataFrame({
    "latitude": [40.0, 29.5, 42.3],
    "longitude": [-100.0, -105.0, -98.4],
    "stid": ["AA", "BB", "CC"]
})
ds_points = ds.herbie.pick_points(stations, method="nearest")

```

All accessor methods are available immediately after loading data through Herbie, requiring no additional imports beyond the standard Herbie and xarray stack.

## Summary

- **Herbie's xarray accessor** (`.herbie`) is registered in [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py) and automatically attaches to Datasets opened via `H.xarray()`.
- **Coordinate utilities** include `to_180()`, `to_360()`, and the `center` property for standardizing spatial references and calculating grid centers.
- **Domain geometry** methods like `polygon` and `crs` leverage Cartopy and Shapely to create boundary polygons and coordinate reference systems from CF metadata.
- **Meteorological calculations** such as `with_wind()` automatically derive wind speed and direction from u/v components with proper CF attributes.
- **Spatial extraction** via `pick_points()` uses `sklearn.neighbors.BallTree` for efficient nearest-neighbor and weighted interpolation, with optional disk caching for repeated queries.

## Frequently Asked Questions

### How do I access Herbie's xarray accessor methods?

Once you load data using `ds = H.xarray(...)`, the Dataset automatically has the `.herbie` namespace available. You can call methods directly via `ds.herbie.method_name()` without any additional imports. The accessor is registered in [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py) using `xr.register_dataset_accessor("herbie")`.

### What is the difference between `pick_points` and `nearest_points`?

`pick_points()` is the modern, recommended method that delegates to `GridPointPicker` in [`src/herbie/pick_points.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/pick_points.py), supporting both nearest-neighbor and weighted interpolation with `sklearn.neighbors.BallTree` indexing and disk caching. `nearest_points()` is a legacy wrapper maintained for backward compatibility that calls the older `herbie.nearest_points` module without the performance optimizations of the newer implementation.

### Does the Herbie accessor modify the original xarray Dataset?

Methods like `to_180()`, `to_360()`, and `with_wind()` return new Dataset objects with modified coordinates or additional variables, following standard xarray conventions. Properties like `center`, `crs`, and `polygon` compute and cache values without altering the underlying dataset structure. The `pick_points` method returns a new Dataset containing extracted point data with attached metadata.

### How does Herbie handle coordinate reference systems?

The `crs` property in [`src/herbie/accessors.py`](https://github.com/blaylockbk/herbie/blob/main/src/herbie/accessors.py) (lines 124-154) lazily parses CF metadata using MetPy's `parse_cf()` method and converts the result to a Cartopy CRS object. This is cached using `@functools.cached_property` to avoid repeated expensive parsing. The resulting CRS can be used directly with Cartopy for map projections or with the `polygon` property to transform domain boundaries between geographic and projected coordinates.