How to Read NASA's Meteorite Landings Data in Python
On this page
Problem statement
NASA's Meteorite Landings table is the most downloaded list of meteorites there is: 45,716 rows, one per meteorite recognised by The Meteoritical Society, with its name, class, mass in grams, whether it was seen to fall or found later, a year and a position. It looks like a clean CSV, and it is easy to map straight away. But nearly a third of the positions are missing or set to 0,0, one meteorite lies on Mars, the years run from 860 to 2101, and NASA last updated the file in May 2013. This page reads it, checks each column and keeps the rows a map can use.
Quick answer
Read the CSV, then drop rows without a position, at 0,0, or with a longitude outside Β±180 before building points:
ok = met.reclat.notna() & ~((met.reclat == 0) & (met.reclong == 0)) & met.reclong.between(-180, 180)
g = gpd.GeoDataFrame(met[ok], geometry=gpd.points_from_xy(met.reclong[ok], met.reclat[ok]), crs=4326)
print(f"usable positions: {len(g):,} of {len(met):,}")
print(g[["name", "recclass", "mass_g", "fall", "year", "reclat", "reclong"]].head(4).to_string(index=False))
usable positions: 32,186 of 45,716
name recclass mass_g fall year reclat reclong
Aachen L5 21.0 Fell 1880.0 50.77500 6.08333
Aarhus H6 720.0 Fell 1951.0 56.18333 10.23333
Abee EH4 107000.0 Fell 1952.0 54.21667 -113.00000
Acapulco Acapulcoite 1914.0 Fell 1976.0 16.88333 -99.90000
32,186 of the 45,716 meteorites have a position a map can use. The first rows are typical of the old, witnessed falls: Aachen, an L5 chondrite of 21 g that fell in 1880, and Abee, an enstatite chondrite of 107,000 g that fell in Alberta in 1952. Mass is in grams, and year is a float because some years are missing.
The columns, one by one
1. Names, ids and status
print(met.columns.tolist())
print(f"ids unique: {met.id.is_unique}; names unique: {met.name.is_unique}")
print(met.nametype.value_counts().to_string())
print(met.fall.value_counts().to_string())
['name', 'id', 'nametype', 'recclass', 'mass_g', 'fall', 'year', 'reclat', 'reclong', 'GeoLocation']
ids unique: True; names unique: True
nametype
Valid 45641
Relict 75
fall
Found 44609
Fell 1107
Both the name and the id are unique, so either is a key. nametype is "Valid" for 45,641 meteorites and "Relict" for 75, objects that were once meteorites but have been weathered beyond classification. fall separates the 1,107 meteorites seen to fall, and collected soon after, from the 44,609 found later with no record of when they arrived.
2. Years
print(met.year.describe().round(1).loc[["count", "min", "50%", "max"]].to_string())
print(met.loc[(met.year > 2013) | (met.year < 1500), ["name", "fall", "year"]].sort_values("year").to_string(index=False))
count 45425.0
min 860.0
50% 1998.0
max 2101.0
name fall year
Nogata Fell 860.0
Narni Fell 920.0
Elbogen Fell 1399.0
Rivolta de Bassi Fell 1490.0
Ensisheim Fell 1491.0
Valdinoce Fell 1495.0
Northwest Africa 7701 Found 2101.0
45,425 rows have a year, with a median of 1998. Six falls date from the Middle Ages: Nogata in Japan in 860, Narni in Italy in 920, and Ensisheim, which fell in Alsace in 1491. At the other end is Northwest Africa 7701, dated 2101, a typing error, since the file stops in 2013. For a find, the year is when it was found or classified, not when it fell.
3. Masses
print(f"no mass: {met.mass_g.isna().sum()}; mass 0: {(met.mass_g == 0).sum()}")
print(met.mass_g.describe(percentiles=[0.25, 0.5, 0.75, 0.99]).round(1).to_string())
no mass: 131; mass 0: 19
count 45585.0
mean 13278.1
std 574988.9
min 0.0
25% 7.2
50% 32.6
75% 202.6
99% 50600.0
max 60000000.0
131 meteorites have no mass and 19 a mass of 0, which means unknown, not weightless. The rest are extremely skewed. The median meteorite weighs 32.6 g, three quarters weigh 202.6 g or less, and the 99th percentile is 50,600 g, while the largest, Hoba, weighs 60 tonnes. The mean of 13,278 g describes almost no meteorite in the table. Work on a log scale or with medians.
4. Positions
print(f"no position: {met.reclat.isna().sum():,}; at 0,0: {((met.reclat == 0) & (met.reclong == 0)).sum():,}; longitude beyond 180: {(met.reclong.abs() > 180).sum()}")
print(met.loc[met.reclong.abs() > 180, ["name", "recclass", "reclat", "reclong", "GeoLocation"]].to_string(index=False))
geo = met.GeoLocation.str.strip("()").str.split(", ", expand=True).astype(float)
print(f"GeoLocation equals reclat, reclong: {(np.isclose(geo[0], met.reclat) & np.isclose(geo[1], met.reclong)).sum():,} of {met.GeoLocation.notna().sum():,}")
no position: 7,315; at 0,0: 6,214; longitude beyond 180: 1
name recclass reclat reclong GeoLocation
Meridiani Planum Iron, IAB complex -1.94617 354.47333 (-1.94617, 354.47333)
GeoLocation equals reclat, reclong: 38,401 of 38,401
7,315 meteorites have no position and 6,214 sit at exactly 0,0, the placeholder for "not given". One row has a longitude of 354.5: Meridiani Planum, an iron meteorite found on Mars by the Opportunity rover, with Martian coordinates. GeoLocation repeats reclat and reclong as text for all 38,401 rows that have it, so it can be ignored. A further 224 rows have only one coordinate at 0, which the quick answer's filter lets through; the 0,0 page deals with them.
Records over time, and where the names come from
The data used on this page
NASA's Meteorite Landings table, compiled from The Meteoritical Society's records and last updated by NASA on 14 May 2013, read from the CSV NASA still serves. It is saved on this site with the rest of the meteorite and fireball data, downloaded on 28 October 2026, so the pages keep working if NASA moves the file again, as it did when its open-data portal was rebuilt. Masses are in grams, positions in decimal degrees.
from pathlib import Path
import json
import zipfile
import geopandas as gpd
import numpy as np
import pandas as pd
import requests
Path("data").mkdir(exist_ok=True)
# NASA's Meteorite Landings table (The Meteoritical Society's records as NASA last updated them, May 2013), every
# fireball in NASA/JPL's Fireball Data API, and Natural Earth's countries and land. Saved 28 October 2026.
# Live: https://data.nasa.gov/docs/legacy/meteorite_landings/Meteorite_Landings.csv
# https://ssd-api.jpl.nasa.gov/fireball.api?vel-comp=true
ARCHIVE = "nasa-meteorites-2026-10-28.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}")
met = pd.read_csv(Z.open("Meteorite_Landings.csv")).rename(columns={"mass (g)": "mass_g"})
for f in ["ne_110m_admin_0_countries.zip", "ne_50m_land.zip"]:
Path(f"data/{f}").write_bytes(Z.read(f))
print(f"Meteorite Landings: {len(met):,} meteorites")
Meteorite Landings: 45,716 meteorites
Example 1: records per year
per = met[met.year.between(1970, 2013)].groupby("year").size()
print(per.loc[[1970, 1979, 1988, 1998, 2003, 2006, 2010, 2012, 2013]].to_string())
print(f"recorded before 1970: {(met.year < 1970).sum():,}; 1970-2013: {per.sum():,}")
for y in [1979, 2003]:
print(y, met[met.year == y].name.str.replace(r"\s*[A-Z]?\d+.*$", "", regex=True).value_counts().head(1).to_dict())
year
1970.0 48
1979.0 3046
1988.0 2296
1998.0 2697
2003.0 3323
2006.0 2456
2010.0 1005
2012.0 234
2013.0 11
recorded before 1970: 2,294; 1970-2013: 43,130
1979 {'Yamato': 2940}
2003 {'Grove Mountains': 1312}
Only 2,294 meteorites carry a year before 1970, and 43,130 from 1970 to 2013. The years jump around: 48 in 1970, 3,046 in 1979, 3,323 in 2003. Those peaks are field seasons, not showers. 2,940 of the 1979 meteorites are named Yamato, collected by a Japanese expedition on the blue ice near the Yamato Mountains in Antarctica, and 1,312 of 2003's come from China's Grove Mountains expedition. The last years are thin, 234 in 2012 and 11 in 2013, because classification lags years behind collection and NASA stopped updating the file.
Example 2: where the names come from
met["place"] = met.name.str.replace(r"\s*[A-Z]?\d+.*$", "", regex=True)
top = met.place.value_counts().head(8)
print(top.to_string())
print(f"meteorites named after these 8 places: {top.sum():,} ({top.sum() / len(met):.1%})")
place
Yamato 7269
Northwest Africa 4499
Queen Alexandra Range 3444
Grove Mountains 2494
Elephant Moraine 2187
Miller Range 2038
Lewis Cliff 1870
Allan Hills 1754
meteorites named after these 8 places: 25,555 (55.9%)
A meteorite is named after the place where it fell or was found, and where many are found together they get the place name and a number, such as Yamato 791197. Stripping the number shows how concentrated the collection is: eight places supply 25,555 meteorites, 55.9% of the table. Seven are in Antarctica. The eighth, Northwest Africa, is not a place but a label for meteorites bought from dealers in Morocco and nearby countries, whose find sites are unknown.
Internal links
- Falls and finds explained β why most meteorites come from Antarctica, and getting the data without code
- Meteorites at 0,0 β the missing positions, and how many can be recovered
- Meteorite classes β 466 class labels in a few groups
- NASA's fireball reports β the meteors seen arriving, from 1988 to now