How to Map Helicopters, Gliders and Balloons by State From the FAA Registry

On this page

Problem statement

The FAA registry codes every aircraft by type: glider, balloon, fixed wing, rotorcraft, weight-shift, powered parachute, gyroplane and hybrid lift. Mapping one type by state shows where each kind of flying happens, such as balloons in New Mexico. But the codes are older than the aircraft now being registered under them. Since large agricultural and delivery drones have to be registered, "rotorcraft" and "hybrid lift" increasingly mean drones, and a state map of rotorcraft is now partly a map of spray drones. This page separates them by engine type and maps helicopters, drones, gliders and balloons with the 16 October 2026 file.

Quick answer

Keep valid US registrations, split rotorcraft by engine (code 10 is electric), and cross-tabulate by state:

us = reg[(reg.COUNTRY == "US") & (reg["STATUS CODE"] == "V") & reg.STATE.isin(STATEFP.index)].copy()
us["kind"] = us["TYPE AIRCRAFT"].map(TYPE_AIRCRAFT)
drone = (us.kind == "rotorcraft") & (us["TYPE ENGINE"] == "10")
us.loc[drone, "kind"] = "electric rotorcraft"
us.loc[us.kind == "rotorcraft", "kind"] = "helicopter"
tab = pd.crosstab(us.STATE, us.kind)
print(tab[["helicopter", "electric rotorcraft", "hybrid lift", "glider", "balloon"]].sum().to_string())
kind
helicopter             14838
electric rotorcraft    12497
hybrid lift             3300
glider                  4802
balloon                 5171

Of the valid rotorcraft, 14,838 have a fuel-burning engine and 12,497 are electric. Electric rotorcraft are almost as numerous as helicopters, and 3,300 more drones sit under hybrid lift.

Bar chart of valid US registrations: 14,838 helicopters with fuel engines, 12,497 electric rotorcraft, 3,300 hybrid lift, 5,171 balloons and 4,802 gliders. Bar chart of valid US registrations: 14,838 helicopters with fuel engines, 12,497 electric rotorcraft, 3,300 hybrid lift, 5,171 balloons and 4,802 gliders.
Rotorcraft split by engine: almost half are electric drones.

Counts, shares and per resident

1. Where each kind is most numerous

for k in ["helicopter", "electric rotorcraft", "glider", "balloon", "gyroplane", "powered parachute"]:
    top = tab[k].nlargest(3)
    print(f"{k:18} " + ", ".join(f"{s} {v:,}" for s, v in top.items()))
helicopter         TX 1,574, FL 1,290, CA 1,260
electric rotorcraft TX 1,164, IA 1,013, OH 804
glider             CA 613, TX 341, FL 278
balloon            NM 613, CO 325, TX 274
gyroplane          TX 54, FL 35, CA 33
powered parachute  TX 159, MI 121, WI 103

Texas leads for helicopters (1,574) and electric rotorcraft (1,164), but Iowa is second for electric rotorcraft with 1,013, more than California or Florida. New Mexico has the most balloons, 613, home of the Albuquerque balloon fiesta; California the most gliders.

2. As a share of each state's aircraft

share = tab.div(tab.sum(axis=1), axis=0)
big = share[tab.sum(axis=1) >= 1000]
for k in ["helicopter", "electric rotorcraft", "balloon"]:
    print(f"{k:19} US {tab[k].sum() / tab.values.sum():.2%}; highest " + ", ".join(f"{s} {v:.1%}" for s, v in big[k].nlargest(3).items()))
helicopter          US 4.85%; highest LA 13.7%, OR 8.8%, MD 8.4%
electric rotorcraft US 4.09%; highest IA 23.1%, NE 14.7%, NJ 14.6%
balloon             US 1.69%; highest NM 19.9%, IA 4.5%, CO 4.4%

As a share of a state's registered aircraft, electric rotorcraft are 23.1% in Iowa, 14.7% in Nebraska and 14.6% in New Jersey. Helicopters are 13.7% in Louisiana, whose offshore platforms are reached by helicopter, and balloons 19.9% in New Mexico.

Map of lower-48 states shaded by registered electric rotorcraft per resident, darkest in Iowa, the Dakotas and Nebraska. Map of lower-48 states shaded by registered electric rotorcraft per resident, darkest in Iowa, the Dakotas and Nebraska.
Registered spray and delivery drones per resident: a Corn Belt map.

3. Per resident

spop = pop.assign(STUSPS=pop.STATE.map({v: k for k, v in STATEFP.items()})).groupby("STUSPS").POPESTIMATE2025.sum()
per = tab.div(spop, axis=0).mul(100_000).dropna()
print("helicopter:", ", ".join(f"{s} {v:.1f}" for s, v in per.helicopter.nlargest(4).items()))
print("electric rotorcraft:", ", ".join(f"{s} {v:.1f}" for s, v in per["electric rotorcraft"].nlargest(4).items()))
print("balloon:", ", ".join(f"{s} {v:.1f}" for s, v in per.balloon.nlargest(4).items()))
helicopter: DE 76.7, AK 53.8, MT 35.4, WY 30.6
electric rotorcraft: IA 31.3, ND 24.1, NE 21.2, SD 16.5
balloon: NM 28.8, SD 7.7, VT 7.4, IA 6.1

Per resident, the electric rotorcraft are a Corn Belt map: Iowa 31.3 per hundred thousand, North Dakota 24.1, Nebraska 21.2, South Dakota 16.5. Helicopters per resident are highest in Delaware, 76.7, an address effect, and in Alaska and Montana. Balloons are 28.8 per hundred thousand in New Mexico, nearly four times the next state.

Engines, and a state map

The data used on this page

The FAA's Releasable Aircraft Database, public domain, downloaded on 16 October 2026 and saved on this site, because the FAA replaces it every day. The saved copy leaves out the owners' names and street addresses and keeps five-digit ZIP codes; every other column is as published. With it come the Census Bureau's Vintage 2025 county population estimates, 2024 county boundaries and 2024 ZCTA gazetteer.

from pathlib import Path
import zipfile

import geopandas as gpd
import numpy as np
import pandas as pd
import requests

Path("data").mkdir(exist_ok=True)
# FAA Releasable Aircraft Database, 16 October 2026: MASTER.txt without the NAME, STREET, STREET2 and OTHER NAMES
# columns and with five-digit ZIP codes (MASTER-no-names.txt), ACFTREF.txt and ENGINE.txt as published; Census
# Vintage 2025 county estimates, 2024 cartographic boundary counties and 2024 ZCTA gazetteer. Saved here unchanged
# otherwise, because the FAA replaces the file daily.
# Live: https://registry.faa.gov/database/ReleasableAircraft.zip (needs a browser User-Agent),
# https://www2.census.gov/geo/docs/maps-data/data/gazetteer/2024_Gazetteer/2024_Gaz_zcta_national.zip
ARCHIVE = "faa-aircraft-registry-2026-10-16.zip"
if not Path(f"data/{ARCHIVE}").exists():
    Path(f"data/{ARCHIVE}").write_bytes(requests.get(f"https://data.spatialworkflow.io/{ARCHIVE}", timeout=600).content)
Z = zipfile.ZipFile(f"data/{ARCHIVE}")


def faa(name):
    """One registry file: comma-separated, every field padded with spaces, a byte-order mark and a trailing comma."""
    d = pd.read_csv(Z.open(name), dtype=str, encoding="utf-8-sig", keep_default_na=False)
    d.columns = d.columns.str.strip()
    d = d.loc[:, [c for c in d.columns if c and not c.startswith("Unnamed")]]
    return d.apply(lambda c: c.str.strip())


reg = faa("MASTER-no-names.txt")
ref = faa("ACFTREF.txt")
TYPE_AIRCRAFT = {"1": "glider", "2": "balloon", "3": "blimp", "4": "fixed wing single engine", "5": "fixed wing multi engine",
                 "6": "rotorcraft", "7": "weight-shift", "8": "powered parachute", "9": "gyroplane", "H": "hybrid lift", "O": "other"}
REGISTRANT = {"1": "individual", "2": "partnership", "3": "corporation", "4": "co-owned", "5": "government", "7": "LLC",
              "8": "non-citizen corporation", "9": "non-citizen co-owned", "": "blank"}
Path("data/cb_2024_us_county_20m.zip").write_bytes(Z.read("cb_2024_us_county_20m.zip"))
counties = gpd.read_file("data/cb_2024_us_county_20m.zip")
STATEFP = counties.drop_duplicates("STUSPS").set_index("STUSPS").STATEFP
pop = pd.read_csv(Z.open("co-est2025-alldata.csv"), encoding="latin-1", dtype={"STATE": str, "COUNTY": str})
pop = pop[pop.SUMLEV == 50].assign(GEOID=lambda p: p.STATE + p.COUNTY)
print(f"FAA registry, 16 October 2026: {len(reg):,} aircraft, {len(ref):,} make-and-model codes")
FAA registry, 16 October 2026: 317,604 aircraft, 94,115 make-and-model codes

Example 1: what the electric rotorcraft are

e = us[us.kind.isin(["electric rotorcraft", "hybrid lift"])].merge(ref[["CODE", "MFR", "MODEL"]], left_on="MFR MDL CODE", right_on="CODE", how="left")
print(e.groupby(["kind", "MFR", "MODEL"]).size().nlargest(6).to_string())
kind                 MFR                        MODEL     
hybrid lift          ZIPLINE INTERNATIONAL INC  P2 ZIP        2979
electric rotorcraft  DJI                        AGRAS T40     1737
                                                AGRAS T50     1442
                                                AGRAS T100     748
                     UVIFY                      810-00028      650
                     AMAZON.COM SERVICES LLC    MK30           615

The electric rotorcraft are DJI Agras T40, T50 and T100 crop-spraying drones, the most common three models, then UVify and Amazon's MK30 delivery drone. Nearly all hybrid-lift aircraft are Zipline P2 delivery drones, 2,979 of them.

Example 2: helicopters on a state map

states = counties[~counties.STUSPS.isin(["AK", "HI", "PR"])].dissolve("STUSPS").to_crs(5070)
m = states.join(per.helicopter.rename("heli"))
print(m.heli.describe()[["min", "50%", "max"]].round(1).to_string())
ax = m.plot(column="heli", cmap="Oranges", legend=True, figsize=(10, 6))
ax.set_axis_off()
min     0.8
50%     3.6
max    76.7
Map of lower-48 states shaded by helicopters per resident, darkest in Montana, Wyoming, Louisiana and Delaware, with Delaware labelled as a registration-address effect. Map of lower-48 states shaded by helicopters per resident, darkest in Montana, Wyoming, Louisiana and Delaware, with Delaware labelled as a registration-address effect.
Helicopters per resident by state; Delaware's figure is registration addresses.

Helicopters per hundred thousand residents range from 0.8 to 76.7 across the lower 48, with a median of 3.6. Delaware's figure is a registration address, not a heliport count; after it come Alaska, 53.8, Montana, 35.4, and Wyoming, 30.6.