Data — Reproduction package
Everything on this site can be regenerated from a single parquet file (3.1 MB). Below: download links, schemas, and example queries.
The cleaned dataset
File: tornadoes.parquet (3.1 MB; 80,626 rows; 1950–2026)
Direct download: /data/tornadoes.parquet
Schema
| Column | Type | Description |
|---|---|---|
event_id | int64 | Storm Events event identifier |
episode_id | int64 (nullable) | Parent episode identifier |
year | int16 | Calendar year |
month | int8 | Calendar month (1–12) |
begin_date | datetime64[ns] | Beginning of event (local time) |
begin_time | str | Beginning of event (HH:MM local time) |
state | str (UPPERCASE) | US state name |
state_fips | str | Two-digit FIPS code (e.g. "40") |
cz_fips | str | County/zone FIPS code |
cz_name | str (UPPERCASE) | County or zone name |
mag_scale | str | F0, F1, ..., F5, EF0, ..., EF5, or empty |
mag_num | float32 | Numeric scale (0–5); null where unrated |
begin_lat | float32 | Touchdown latitude (decimal degrees, may be null) |
begin_lon | float32 | Touchdown longitude (decimal degrees, may be null) |
end_lat | float32 | Liftoff latitude (may be null) |
end_lon | float32 | Liftoff longitude (may be null) |
tor_length | float32 | Path length (miles) |
tor_width | float32 | Path width (yards) |
injuries_dir | Int32 | Direct injuries |
injuries_indir | Int32 | Indirect injuries |
deaths_dir | Int32 | Direct deaths |
deaths_indir | Int32 | Indirect deaths |
damage_prop | str | Raw damage property (e.g. "25K", "1.5M") |
damage_crops | str | Raw damage crops |
wfo | str | NWS Weather Forecast Office |
source | str | Reporting source |
Quickstart (Python)
import pandas as pd
df = pd.read_parquet("tornadoes.parquet")
# Count by year
df.groupby("year").size()
# Filter to F/EF1+
sig = df[df.mag_num >= 1]
# Compute the headline centroid shift
p1_lat = sig[sig.year <= 1985].begin_lat.mean()
p1_lon = sig[sig.year <= 1985].begin_lon.mean()
p3_lat = sig[sig.year >= 2001].begin_lat.mean()
p3_lon = sig[sig.year >= 2001].begin_lon.mean()
shift_miles = 69 * ((p3_lat - p1_lat)**2 + (p3_lon - p1_lon)**2) ** 0.5
print(f"Shift: {shift_miles:.1f} mi")
# Output: Shift: 70.0 mi
Aggregated CSV files
For users who don't need the full parquet:
- by_year.csv — annual counts, totals, intensities, casualties (78 rows: 1950–2024, plus 2025–2026 working rows)
- by_state_year.csv — per-state per-year counts (≈4,500 rows)
- by_state_era.csv — per-state P1/P2/P3 totals with per-year means and the P3:P1 ratio (54 rows)
Headline JSON
A condensed summary of every metric on this site:
Use this for quick checks or for driving an alternate visualization.
Source attribution
All data is from the NOAA Storm Events Database, downloaded 2026-07-12 from https://www.ncei.noaa.gov/pub/data/swdi/stormevents/csvfiles/. Bulk downloads are organized as StormEvents_details-ftp_v1.0_d<YEAR>_c<DATE>.csv.gz, one per calendar year, 1950 through present.
We do not redistribute NOAA data without attribution. The cleaned parquet file is a re-organization of the public NCEI release; it adds derived columns (year from BEGIN_DATE_TIME, month from BEGIN_DATE_TIME, mag_num from TOR_F_SCALE) but does not modify any underlying values.