Storm Events annual tables
Available since v0.8 as noaa:storm-events. Anonymous NCEI bulk access returns
whole annual tables, compressed with gzip. The default is the details table,
one row per event. -p table=fatalities and -p table=locations select its two
siblings, which NCEI publishes in the same directory under the same naming and
revision scheme (available since v0.22.0). The adapter
supports schema v1.0; it does not guess how to interpret a newer schema.
The three tables
table |
One row per | Columns |
|---|---|---|
details (default) |
event | the event record: type, place, times, impacts, narratives |
fatalities |
death | FAT_YEARMONTH, FAT_DAY, FAT_TIME, FATALITY_ID, EVENT_ID, FATALITY_TYPE, FATALITY_DATE, FATALITY_AGE, FATALITY_SEX, FATALITY_LOCATION |
locations |
point of an event | YEARMONTH, EPISODE_ID, EVENT_ID, LOCATION_INDEX, RANGE, AZIMUTH, LOCATION, LATITUDE, LONGITUDE, LAT2, LON2 |
EVENT_ID joins both to details; nothing is joined for you. An event has no
fatalities row unless someone died, and may have several location rows, numbered
by LOCATION_INDEX: the 6 May 2024 Osage County EF4 (event 1184254) has two
of each. A location is a named place with the RANGE in miles and AZIMUTH
from it, plus the point itself in decimal degrees; LAT2 and LON2 repeat it
in a packed degrees-and-minutes form. Those points partly fill the gap between
the start and end coordinates on a details row and a surveyed damage path.
Checked on 2026-09-18: all three tables have a file for every year from 1950 to 2026. Fatalities rows exist throughout (11 in 1950). The locations files hold rows only from 1996; each earlier one is a header and nothing else, so an early-year request succeeds and opens as an empty frame rather than failing. The tables of one year are revised together and carry the same creation date.
Both dates are required and interpreted in UTC for annual file selection.
Every calendar year touched is returned in full: May 1–31 selects the complete
year; December 31–January 1 selects both years. Asset time bounds label those
whole file years, not precise coverage of local event timestamps. The files
are split by each event's local begin date, so an event early on January 1 UTC
can sit in the previous year's file: at UTC−6 it is still December 31 until
06:00 UTC, and at UTC−11 until 11:00 UTC; Guam, at UTC+10, is already in the
next year from 14:00 UTC on December 31. A window within those hours of a new
year selects only one file; start it a day earlier, or end it a day later, to
fetch both. Dates before 1950 and a missing requested year are errors, so a multi-year request cannot
silently succeed with only some years. Location/bbox, variables, and text are
rejected, and table is the only parameter, so spatial_subset and
variable_subset are false: selecting an annual object performs no server-side
row subsetting. Only temporal_subset is true, because the requested dates
choose which annual objects are returned.
The directory lists filenames such as
StormEvents_details-ftp_v1.0_d2024_c20260728.csv.gz: d identifies the data year
and c the creation date. Resolution chooses the greatest valid creation date
per year. The complete filename is the stable asset ID; URL, original compressed
bytes, size, and checksum are preserved. Exact integer directory sizes are used
when present; approximate sizes are left unknown. A lockfile restores its pinned
URL without listing current revisions, so pull --force is what moves to a
newer annual revision.
Upstream revisions
Agencies revise files in place. A locked restore downloads each pinned URL
and fails with a checksum mismatch when the bytes have changed; accept the
new bytes for chosen entries with pull --update, or re-resolve the whole
manifest with pull --force. A lockfile detects changed data; it does not
archive it. Keep the cache with the manifest and lockfile. See
provenance and drift.
FetchedAsset.open() uses the pandas extra and a local gzip stream. It preserves
raw identifier strings and records source provenance in DataFrame attributes;
it does not decompress into the cache. EVENT_ID identifies event records,
while EPISODE_ID can group several events. CZ_TYPE distinguishes county,
forecast-zone, and marine records; CZ_FIPS is not always a county code.
Dates/times in rows are local, with CZ_TIMEZONE needed for instant conversion.
The executed notebook filters on
reported calendar dates and keeps timezone labels visible.
The timezone rule
CZ_TIMEZONE is a local-standard-time label ending in its whole-hour UTC
offset, so CST-6 is UTC−6 and Guam's GST10, which omits the sign, is UTC+10.
The labels seen in the annual files are CST-6, EST-5, MST-7, PST-8,
AST-4, AKST-9, HST-10, SST-11, and GST10, plus a few daylight spellings
(CDT-5, EDT-4, PDT-7) whose trailing offset is still the one to use. No
Python timezone accepts these strings, and applying a named regional zone would
add daylight saving the reports do not use.
Files through 2006 write the label bare, with no offset: CST, not CST-6.
Eight bare labels name one offset wherever they appear in the archive and are
converted with it: CST −6, EST −5, MST −7, PST −8, and HST −10, and
the daylight labels CDT −5, EDT −4, and MDT −6, a few rows a year, read at
their word as CDT-5 is. The rest are left unconverted rather than guessed
(ADR 0033):
ASTlabels both Alaska (UTC−9) and Puerto Rico and the Virgin Islands (UTC−4).SSTlabels both American Samoa (UTC−11) and Guam (UTC+10).UNKsays nothing.
STATE tells the first two apart, so a caller who needs those rows can convert
them by hand. The local timestamps carry two-digit years; 50 to 99 are read
as 1950 to 1999, since the archive begins in 1950, where the usual pivot would
put its first nineteen years a century late.
When the frame keeps CZ_TIMEZONE, open() and open_csv() add BEGIN_UTC
for a kept BEGIN_DATE_TIME and END_UTC for a kept END_DATE_TIME, as
timezone-aware UTC timestamps, leaving the original columns alone. A frame that
keeps a local column without CZ_TIMEZONE gets no UTC column and a
UserWarning naming what to add to usecols. A row whose label yields no offset, or whose
timestamp does not parse, gets NaT. frame.attrs["usdata"]["derived"] lists,
per derived column, the rule used, the count of such rows as unparsed, and
under labels_without_offset each label that gave no offset with how many rows
carry it.
frame = item.open_csv(usecols=["EVENT_ID", "BEGIN_DATE_TIME", "END_DATE_TIME", "CZ_TIMEZONE"])
print(frame[["BEGIN_DATE_TIME", "CZ_TIMEZONE", "BEGIN_UTC", "END_UTC"]].head())
print(frame.attrs["usdata"]["derived"]) # column, source, rule, unparsed, labels_without_offset
hours = pd.to_numeric(frame.CZ_TIMEZONE.str.extract(r"^[A-Za-z]+([+-]?\d{1,2})$", expand=False))
local = pd.to_datetime(frame.BEGIN_DATE_TIME, format="%d-%b-%y %H:%M:%S", errors="coerce")
The last two lines are the manual form for files from 2007 on: subtract
pd.to_timedelta(hours, unit="h") from local and call .dt.tz_localize("UTC")
to get the same instants without the reader. Earlier files also need the bare
labels mapped and, before 1969, the century corrected, which %y gets wrong.
Reported events, impacts, and damage ratings require care when aggregating: physical storms can span several records, historical reporting varies, and missing reports do not establish an absence of hazards. Source field meanings are documented in the NCEI bulk format reference. The archive README describes filenames and revisions; dataset metadata describes historical coverage.
See the service research notes for dated upstream probes.
Metadata sources
Every value in the catalog entry's resolution, cadence, citation, terms, variables, and limits comes from one of these pages. A field the agency does not publish is left empty rather than estimated.
- Updates: the archive README, which says the current yearly file is updated each month.
- Resolution and variables: the NCEI bulk format reference for the record granularity and the identifying columns this guide names. The full column set is larger.
- Terms and citation: the NCEI dataset record, whose use constraint is only "cite dataset when used as a source", so the entry uses the agency, product, and access form.
- Latency is empty: neither the README nor the dataset record states how far behind the present the files run.
Reference
noaa:storm-events · Released · Included since usdata 0.8. Storm Events Database.
At a glance
- Files: gzip CSV
- Selection: Whole annual archives of one table; filter rows locally after downloading
- Required inputs: Both dates (selects the containing years); optionally table
- Open locally:
usdata[pandas]· Reader guide - On usdata.dev: Storm Events details, fatalities, and locations, with a walkthrough
- Studies: What did radar and satellites show around a reported tornado?; Which severe reports came with rotation and lightning?; For one Oklahoma tornado, do the two report archives agree on when and where it was, and what did radar, lightning, and the model analysis show at that place and time?; How long before the 6 May 2024 Osage County tornado was a tornado warning issued?; Which Oklahoma counties hit by a tornado on 6 May 2024 were under a federal disaster declaration?
Parameters
Pass these as --param name=value to the CLI, as params: entries in a manifest, or as keyword arguments to build_query.
| Parameter | Meaning |
|---|---|
table |
Annual table: details (default, one row per event), fatalities (one row per death), or locations (points per event, from 1996); EVENT_ID joins them. |
Variables
| Variable | Units | Meaning |
|---|---|---|
EVENT_ID |
— | Identifier of one event record |
EPISODE_ID |
— | Identifier grouping the events of one storm episode |
CZ_TYPE |
— | County (C), forecast zone (Z), or marine (M) record |
CZ_FIPS |
— | County or zone code; not always a county FIPS code |
CZ_TIMEZONE |
— | Time zone of the record's local timestamps |
TOR_F_SCALE |
— | Tornado rating as text, such as EF1 |
Catalog facts
- Availability: since 0.8
- Domain: Severe weather
- Spatial resolution: One record per county, forecast zone, or marine zone touched by an event
- Temporal resolution: One record per reported event, timestamped in the reporting office's local time
- Updates: The current year's file is updated each month
- Terms of use: https://www.ncei.noaa.gov/metadata/geoportal/rest/metadata/item/gov.noaa.ncdc:C00510/html
- Citation: NOAA National Centers for Environmental Information, Storm Events Database, accessed via usdata
- Catalog date range: 1950-01-01 to open-ended
- Coverage varies by station, product, and date; the range above does not guarantee observations.
- Upstream documentation
- License: US Government Work (public domain)
- Transport:
http - Adapter:
usdata.providers.noaa.storm_events:StormEvents