Skip to content

Reader options

How each reader behaves is explained in readers. This page lists what to install, what open() infers, and what each format's method accepts.

Readers and extras

Format Method Extra Returns Inferred for
CSV open_csv pandas pandas DataFrame text/csv, application/csv (charset parameters allowed); application/gzip or application/x-gzip when the id ends in .csv.gz
ERDDAP CSV open_csv pandas pandas DataFrame with attrs["units"] CSV media types on an asset whose protocol is ERDDAP, and noaa:ibtracs CSV assets, whose units row has the same layout; for IBTrACS only a single space or an empty field is missing, so the basin code NA stays text
HURDAT2 open() only pandas pandas DataFrame, one row per track point noaa:hurdat2 assets, or ids hurdat2-*.txt
AQS daily JSON open() only pandas pandas DataFrame, one row per monitor, local day, and pollutant standard; date_local and date_of_last_change as naive dates, the header in attrs["usdata"]["header"] epa:aqs-daily assets, or ids aqs-daily_*.json
ACS table open() only pandas pandas DataFrame, one row per geography; estimate and margin-of-error columns as numbers with annotation codes kept, other columns as text census:acs-5year assets, or ids acs5_*.json
NEXRAD Level II open_nexrad radar xarray DataTree noaa:nexrad-level2 assets
NetCDF4 open_netcdf netcdf xarray Dataset application/x-netcdf, application/netcdf, application/x-netcdf4
GRIB2 open_grib2 grib xarray Dataset application/x-grib2, application/grib2, application/x-grib, application/wmo-grib2; ids ending .grib2, .grb2, or their .gz forms when the media type is missing, generic, or gzip

noaa:nexrad-level3 assets have no reader and open() raises UnsupportedFormat. Install extras as pip install "usdata[pandas,grib]"; the Install page has the platform notes for grib.

Options

open() takes no options. Each format with options has its own method on FetchedAsset, and a function of the same name in usdata.readers that takes the fetched asset first. A method opens the file as that format whatever its metadata says, so it is also how a file with ambiguous metadata is opened. HURDAT2, AQS, and ACS files take no options and are opened with open().

Method Returns Option Behavior
open_csv pandas DataFrame dtype Mapping of column names to pandas dtype strings; overrides the identifier defaults below.
parse_dates Columns to parse as dates. Nothing is parsed by default; dtype={"DATE": "string"} keeps numeric-looking labels as text.
usecols Columns to read, in pandas order.
nrows Maximum observation rows, excluding header and units rows.
units_row Whether a units row follows the header, as in ERDDAP CSV; None, the default, infers it as open() does.
open_nexrad xarray DataTree sweep Zero-based integer or non-empty list of distinct integers; None opens every sweep.
open_grib2 xarray Dataset select Mapping of ecCodes key names to one value or a list of values; required when a file holds more than one message.
strict True raises when a select value matches none of the selected messages; the default warns and returns the rest.
open_netcdf xarray Dataset No options.

The return types are declared for type checkers, so an editor knows what each method returns once the extra that provides the type is installed; open() returns Any because its result depends on the file.

NEXRAD sweeps

open_nexrad(sweep=...) takes positions in the volume, not elevations. A split cut scans one angle twice, once for reflectivity and the dual-polarization moments and once for velocity and spectrum width, and SAILS or MRLE rescan the lowest angles inside a volume, so in a VCP 212 volume with three SAILS cuts the 0.5° angle is sweeps 0, 1, 4, 5, 9, 10, 16, and 17. Which index holds which angle changes with the volume coverage pattern.

readers.nexrad_sweeps(path) lists every sweep from the volume's metadata without decoding a moment, in under half the time decoding one sweep takes: its index, VCP cut (elevation_number), fixed_angle, the moments open_nexrad returns for it, start and end times, ray count, whether it is complete, and whether it is a sails or mrle rescan. FetchedAsset.inspect() returns the same list with the VCP number as nexrad, and usdata inspect prints it as a table. Choose sweeps there, then open them by index:

from usdata.readers import nexrad_sweeps

sweeps = nexrad_sweeps(item.path)
lowest = min(sweep.fixed_angle for sweep in sweeps)
velocity = [s.index for s in sweeps if s.fixed_angle == lowest and "VRADH" in s.moments]
radar = item.open_nexrad(sweep=velocity)  # every lowest-angle velocity scan, SAILS included

fixed_angle is the VCP table's angle for the cut, the value open_nexrad puts in sweep_fixed_angle; a legacy volume with no VCP table gives its first ray's elevation and leaves vcp, sails, and mrle as None. A legacy volume's spectrum width is in the file but xradar 0.12 does not decode it, so the listing leaves WRADH out there too.

GRIB2 variable names

Variables are named by shortName when every selected message shares one typeOfLevel and level, and by shortName_typeOfLevel_level for all of them as soon as the selection spans more than one, so the names follow from the select rather than from which short names happened to repeat.

GRIB2 message numbering

A message carries two numbers, and they are not the same. file_index is its zero-based position in the local file, which is what usdata inspect prints and what readers.inventory counts. object_index is the one-based number the source object's .idx sidecar gave it, so it survives only where a partial fetch recorded which messages it took; it is None for a whole file. Both appear on GribMessage and in attrs["usdata"]["messages"], and usdata inspect prints the object # column only when the file has one.

A GRIB2 message can hold several fields; RAP packs wind components that way, and its index numbers them 12.1 and 12.2. The reader opens every field (ecCodes multi-field support is switched on for the process when the reader loads). The fields of one message share its file_index and object_index, and each carries its own selector: the one that named it, or its index line's own selector when it was fetched only because it shares the message. A file pinned before fields were recorded gives them their message's one selector. A gzip-compressed file, which is how MRMS arrives, is read one field per message.

GRIB2 selectors and variable names

A partial fetch also records the index selector each field was fetched for, which usdata inspect prints in a selector column and the reader puts on each messages entry. Grib2Summary.variable_for(selector) turns one of those selectors into the variable name the naming rule above gives that message, so a notebook that asked for CAPE:surface can look up the cape_surface_0 it became instead of guessing it; a selector this file holds no message for raises KeyError naming the ones it does, and one that names a field of a several-field message in a file pinned before fields were recorded raises ValueError rather than guess which field it meant. Both start from each message's base_name on GribMessage: its shortName, or for a parameter ecCodes has no name for, the MRMS product or parameter_<discipline>_<category>_<number>.

An MRMS file is fetched by product, not by selector, so variable_for has nothing to look up there. Its one variable is the product without the nominal-height suffix the directory name carries, RotationTrackML30min for RotationTrackML30min_00.50; (name,) = grid.data_vars reads it without spelling it. The suffix is dropped because it is part of the directory name rather than the quantity, and one product, LightningProbabilityNext30minGrid_scale_1, has none.

CSV identifier defaults

These column names, matched case-insensitively, default to pandas string dtype so leading zeros survive: STATION, station_id, site_no, monitoring_location_id, parameter_code, statistic_id, event_id, episode_id, state_fips, cz_fips, tor_other_cz_fips. No padding is added; other numeric-looking ids need an explicit dtype. Other columns use pandas inference and default missing-value parsing.

Result attributes

Format Where Contents
CSV, HURDAT2, AQS, ACS frame.attrs["usdata"] Asset id, the asset's request properties (a mapping, empty when it records none), and a JSON-compatible copy of its provenance
CSV with a units row frame.attrs["units"] Units row, filtered to the selected columns
NEXRAD Level II radar.attrs["usdata"] Asset id, properties, provenance, and sweeps listing the returned groups
NetCDF4, GRIB2 dataset.attrs["usdata"] Asset id, properties, and provenance
GRIB2 dataset.attrs["usdata"]["messages"] Each variable name mapped to its message's file_index, object_index, shortName, typeOfLevel, level, and step, plus the selector a partial fetch asked for
grib2 per-variable attrs units in UDUNITS notation (J kg-1 where ecCodes writes J kg**-1, with the file's spelling in GRIB_units whenever the two differ), name, typeOfLevel, level, discipline, category, and parameter numbers, packing type, reference and valid times, step; projection parameters on the Dataset for projected grids

Errors

Error From usdata.readers Raised when
MissingReaderDependency subclass of ImportError The extra is not installed; the message names it, and for grib also names the ecCodes library when the binding is present but the library is not
UnsupportedFormat subclass of ValueError open() finds no reader for the asset, or the asset is a Level III product
RadarDecodeError subclass of ValueError Moment and coordinate records do not align for the requested sweeps
Hurdat2FormatError subclass of ValueError A HURDAT2 line, count, or value cannot be parsed; the message names the line
ValueError built-in A multi-message GRIB2 file opened without select, a select that matches no message at all, selected messages on different grids, or, under strict, a select value that matched none of them

Missing local files and pandas, xarray, or ecCodes parsing failures propagate unchanged. CSV headers must be unique and non-empty, and an ERDDAP units row must match the header width.