NASA API: World Map of Fireball Impacts¶
Overview¶
This notebook will cover all the steps to access bright meteor and fireball impact data collected by NASA’s CNEOS and produce a global plot of impact sites
- Prerequisites
- CNEOS Overview
- Imports
- Access and Organize Data
- Plot Earth Fireball Impacts
- Summary
Prerequisites¶
Concepts | Importance | Notes |
---|---|---|
Intro to Matplotlib | Necessary | Plotting on a data |
Intro to GeoPandas | Necessary | Plotting on a world map |
Intro to Pandas | Necessary | Familiarity with working with dataframes |
CNEOS Overivew¶
A shooting star is a common term for a meteor and form bright trails of light that are often bright enough to be visible during the day. A “fireball” is a term for expectionally bright meteor that enters the Earth’s atmosphere at high speeds. A meteor that form fireballs can be over one meter long. A “bolide” typically refers to a fireball that breaks up in the atmosphere. These objects are tracked by the Center for Near Earth Object Studies (CNEOS) and information about the Peak Brightness, Velocity, and Joules of energy radiatated can be retrieved from CNEOS via an API
Fireball Data API¶
This notebook will query the Fireball API for data from the last decade of observations
JPL’s Center for Near-Earth Objects Studies API “Fireball” is an API that will return machine-readable data in the form of a JSON.
All queries to the Fireball Data API make requests to https://ssd-api.jpl.nasa.gov/fireball.api
The API accepts different query parameters to filter the data
Directly querying https://ssd-api.jpl.nasa.gov/fireball.api
will return all the data of fireball impacts in reverse-chronological order
Parameter | Type | Description |
---|---|---|
date-min | string | exclude data earlier than this date YYYY-MM-DD or date/time YYYY-MM-DDThh:mm:ss |
date-max | string | exclude data later than this date YYYY-MM-DD or date/time YYYY-MM-DDThh:mm:ss |
energy-min | string | exclude data with total-radiated-energy less than this positive value in joules ×1010 (e.g., 0.3 = 0.3×1010 joules) |
energy-max | string | exclude data with total-radiated-energy greater than this (see energy-min) |
impact-e-min | string | exclude data with estimated impact energy less than this positive value in kilotons (kt) (e.g., 0.08 kt) |
impact-e-max | string | exclude data with total-radiated-energy greater than this (see impact-e-min) |
alt-min | number | exclude data from objects with an altitude less than this (e.g., 22 meaning objects smaller than this) |
alt-max | number | exclude data from objects with an altitude greater than this (e.g., 17.75 meaning objects larger than this) |
req-loc | boolean | location (latitude and longitude) required; when set true , exclude data without a location |
req-alt | boolean | altitude required; when set true , exclude data without an altitude |
req-vel-comp | boolean | pre-entry velocity components required; when set true , exclude data without pre-entry velocity components |
vel-comp | boolean | include pre-entry velocity components |
sort | string | sort data on the specified field: “date”, “energy”, “impact-e”, “vel”, or “alt” (default sort order is ascending: prepend “-“ for descending) |
limit | number | limit data to the first N results (where N is the specified number and must be an integer value greater than zero) |
Results from API will be returned as JSON with a number of fields
Field | Description |
---|---|
date | date/time of peak brightness (GMT) |
lat | latitude at peak brightness (degrees) |
lon | longitude at peak brightness (degrees) |
lat-dir | latitude direction (“N” or “S”) |
lon-dir | latitude direction (“E” or “W”) |
alt | altitude above the geoid at peak brightness (km) |
energy | approximate total radiated energy (10^10 joules) |
impact-e | approximate total impact energy (kt) |
vx | pre-entry velocity (Earth centered X component, km/s) |
vy | pre-entry velocity (Earth centered Y component, km/s) |
vz | pre-entry velocity (Earth centered Z component, km/s) |
Example JSON result¶
Return the last 3 records https://ssd-api.jpl.nasa.gov/fireball.api?limit=3
{
"signature":
{
"version":"1.0",
"source":"NASA/JPL Fireball Data API"
},
"count":"3",
"fields":["date","energy","impact-e","lat","lat-dir","lon","lon-dir","alt","vel"],
"data":[
["2024-06-03 01:13:51","2.6","0.092","63.1","S","53.2","W","60.0",null],
["2024-06-01 23:24:59","7.9","0.25","1.0","S","15.9","W","26.5","12.6"],
["2024-05-27 03:19:36","8.4","0.26","1.7","N","39.4","W","56.0","39.2"]
]
}
Imports¶
import requests # submit API request query
import pandas as pd # organizes data retrieved by the API
import geopandas # generate a world map
import matplotlib.pyplot as plt # plotting data
Request Fireball Data via API¶
To retrieve all the fireballs recorded in the last decade (2014-2024)
data_since = "2014-01-01"
last_decade_fireball = requests.get(f"https://ssd-api.jpl.nasa.gov/fireball.api?date-min={data_since}")
last_decade_fireball.status_code # 200 is a valid request
200
fireball_json = last_decade_fireball.json()
# print out data labels
print(f"fields = {fireball_json['fields']}")
fields = ['date', 'energy', 'impact-e', 'lat', 'lat-dir', 'lon', 'lon-dir', 'alt', 'vel']
# convert JSON data to a Pandas dataframe
fireball_df = pd.DataFrame(fireball_json["data"], columns=fireball_json["fields"])
fireball_df
# remove nan and duplicated data rows and reindex rows
fireball_df.dropna(inplace=True, ignore_index=True)
# convert columnss from strings to a float
fireball_df["energy"] = fireball_df["energy"].astype(float)
fireball_df["impact-e"] = fireball_df["impact-e"].astype(float)
fireball_df["lat"] = fireball_df["lat"].astype(float)
fireball_df["lon"] = fireball_df["lon"].astype(float)
fireball_df["alt"] = fireball_df["alt"].astype(float)
fireball_df["vel"] = fireball_df["vel"].astype(float)
# convert latitude to negative if lat-dir is S and longitude to negative if lon-dir is W
fireball_df['lat'] = fireball_df['lat'].mask(fireball_df['lat-dir'].eq('S'), -fireball_df['lat'])
fireball_df['lon'] = fireball_df['lon'].mask(fireball_df['lon-dir'].eq('W'), -fireball_df['lon'])
# rename columns
fireball_df = fireball_df.rename(columns= {"impact-e": "impact energy",
"lat": "latitude",
"lat-dir": "latitude direction",
"lon": "longitude",
"lon-dir": "longitude direction",
"alt": "altitude",
"vel": "velocity"})
fireball_df
fireball_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 240 entries, 0 to 239
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 date 240 non-null object
1 energy 240 non-null float64
2 impact energy 240 non-null float64
3 latitude 240 non-null float64
4 latitude direction 240 non-null object
5 longitude 240 non-null float64
6 longitude direction 240 non-null object
7 altitude 240 non-null float64
8 velocity 240 non-null float64
dtypes: float64(6), object(3)
memory usage: 17.0+ KB
Plot the Energy of Fireballs¶
# retrieve world map from GeoPandas
world_map = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
# Set up world map plot
fig, ax = plt.subplots(figsize=(15, 10))
world_map.plot(color="grey", ax=ax)
# Plot Fireball Locations with Energy
x = fireball_df["longitude"]
y = fireball_df["latitude"]
z = fireball_df["energy"]
plt.scatter(x, y, s=5*z, c=z, cmap="autumn")
plt.colorbar(label="Approximate Total Radiated Energy (10^10 Joules)")
# Setup Axis Limits and Title/Labels
plt.xlim([-180, 180])
plt.ylim([-90, 90])
plt.title("Energy of Fireball Observations")
plt.xlabel("Longitude (Degrees)")
plt.ylabel("Latitude (Degrees)")
plt.show()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[8], line 2
1 # retrieve world map from GeoPandas
----> 2 world_map = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
4 # Set up world map plot
5 fig, ax = plt.subplots(figsize=(15, 10))
File ~/micromamba/envs/api-cookbook-dev/lib/python3.13/site-packages/geopandas/datasets/__init__.py:18, in get_path(dataset)
12 error_msg = (
13 "The geopandas.dataset has been deprecated and was removed in GeoPandas "
14 f"1.0. You can get the original '{dataset}' data from "
15 f"{ne_message if 'natural' in dataset else nybb_message}"
16 )
17 if dataset in _prev_available:
---> 18 raise AttributeError(error_msg)
19 else:
20 error_msg = (
21 "The geopandas.dataset has been deprecated and "
22 "was removed in GeoPandas 1.0. New sample datasets are now available "
23 "in the geodatasets package (https://geodatasets.readthedocs.io/en/latest/)"
24 )
AttributeError: The geopandas.dataset has been deprecated and was removed in GeoPandas 1.0. You can get the original 'naturalearth_lowres' data from https://www.naturalearthdata.com/downloads/110m-cultural-vectors/.
Plot the Impact Energy of Fireballs¶
# retrieve world map from GeoPandas
world_map = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
# Set up world map plot
fig, ax = plt.subplots(figsize=(15, 10))
world_map.plot(color="grey", ax=ax)
# Plot Fireball Locations with Energy
x = fireball_df["longitude"]
y = fireball_df["latitude"]
z = fireball_df["impact energy"]
plt.scatter(x, y, s=5*z, c=z, cmap="autumn")
plt.colorbar(label="Approximate Total Impact Energy (kt)")
# Setup Axis Limits and Title/Labels
plt.xlim([-180, 180])
plt.ylim([-90, 90])
plt.title("Total Impact Energy of Fireball Observations")
plt.xlabel("Longitude (Degrees)")
plt.ylabel("Latitude (Degrees)")
plt.show()
Plot the Velocity of Fireballs¶
# retrieve world map from GeoPandas
world_map = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
# Set up world map plot
fig, ax = plt.subplots(figsize=(15, 10))
world_map.plot(color="grey", ax=ax)
# Plot Fireball Locations with Velocity
x = fireball_df["longitude"]
y = fireball_df["latitude"]
z = fireball_df["velocity"]
plt.scatter(x, y, s=5*z, c=z, cmap="winter")
plt.colorbar(label="Pre-Entry Velocity (km/s)")
# Setup Axis Limits and Title/Labels
plt.xlim([-180, 180])
plt.ylim([-90, 90])
plt.title("Pre-Entry Velocity of Fireball Observations")
plt.xlabel("Longitude (Degrees)")
plt.ylabel("Latitude (Degrees)")
plt.show()
Plot the Altitude of Fireballs¶
# retrieve world map from GeoPandas
world_map = geopandas.read_file(geopandas.datasets.get_path("naturalearth_lowres"))
# Set up world map plot
fig, ax = plt.subplots(figsize=(15, 10))
world_map.plot(color="grey", ax=ax)
# Plot Fireball Locations with Energy
x = fireball_df["longitude"]
y = fireball_df["latitude"]
z = fireball_df["altitude"]
plt.scatter(x, y, s=5*z, c=z, cmap="bone")
plt.colorbar(label="Altitude Above Geoid at Peak Brightness (km)")
# Setup Axis Limits and Title/Labels
plt.xlim([-180, 180])
plt.ylim([-90, 90])
plt.title("Altitude of Fireball Observations")
plt.xlabel("Longitude (Degrees)")
plt.ylabel("Latitude (Degrees)")
plt.show()
Last Section¶
If you’re comfortable, and as we briefly used for our embedded logo up top, you can embed raw html into Jupyter Markdown cells (edit to see):
Info
Your relevant information here!Feel free to copy this around and edit or play around with yourself. Some other admonitions
you can put in:
Success
We got this done after all!Warning
Be careful!Danger
Scary stuff be here.We also suggest checking out Jupyter Book’s brief demonstration on adding cell tags to your cells in Jupyter Notebook, Lab, or manually. Using these cell tags can allow you to customize how your code content is displayed and even demonstrate errors without altogether crashing our loyal army of machines!
Summary¶
Add one final ---
marking the end of your body of content, and then conclude with a brief single paragraph summarizing at a high level the key pieces that were learned and how they tied to your objectives. Look to reiterate what the most important takeaways were.
What’s next?¶
Let Jupyter book tie this to the next (sequential) piece of content that people could move on to down below and in the sidebar. However, if this page uniquely enables your reader to tackle other nonsequential concepts throughout this book, or even external content, link to it here!
Resources and references¶
- More information about plotting a world map with GeoPandas