Spaces:
Running
Running
import requests | |
import json | |
from datetime import datetime, timedelta | |
import gradio as gr | |
import pandas as pd | |
import plotly.express as px | |
import plotly.graph_objects as go | |
class NasaSsdCneosApi: | |
""" | |
A class to interact with NASA's SSD/CNEOS API. | |
Provides methods to access data on near-Earth objects, close approaches, and more. | |
""" | |
def __init__(self): | |
self.base_url = "https://ssd-api.jpl.nasa.gov" | |
self.cneos_url = f"{self.base_url}/cneos" | |
self.fireball_url = f"{self.cneos_url}/fireballs" | |
self.ca_url = f"{self.cneos_url}/close_approaches" | |
self.nea_url = f"{self.cneos_url}/nea" | |
self.scout_url = f"{self.cneos_url}/scout" | |
def get_fireballs(self, limit=10, date_min=None, energy_min=None): | |
"""Get information about recent fireballs""" | |
params = {'limit': limit} | |
if date_min: | |
params['date-min'] = date_min | |
if energy_min: | |
params['energy-min'] = energy_min | |
response = requests.get(self.fireball_url, params=params) | |
if response.status_code == 200: | |
return response.json() | |
else: | |
print(f"Error: {response.status_code}") | |
return None | |
def get_close_approaches(self, dist_max=None, date_min=None, date_max=None, | |
h_min=None, h_max=None, v_inf_min=None, v_inf_max=None, | |
limit=10): | |
"""Get information about close approaches of near-Earth objects""" | |
params = {'limit': limit} | |
if dist_max: | |
params['dist-max'] = dist_max | |
if date_min: | |
params['date-min'] = date_min | |
if date_max: | |
params['date-max'] = date_max | |
if h_min: | |
params['h-min'] = h_min | |
if h_max: | |
params['h-max'] = h_max | |
if v_inf_min: | |
params['v-inf-min'] = v_inf_min | |
if v_inf_max: | |
params['v-inf-max'] = v_inf_max | |
response = requests.get(self.ca_url, params=params) | |
if response.status_code == 200: | |
return response.json() | |
else: | |
print(f"Error: {response.status_code}") | |
return None | |
def get_nea_data(self, spk_id=None, des=None, h_max=None): | |
"""Get data about specific near-Earth asteroids""" | |
params = {} | |
if spk_id: | |
params['spk-id'] = spk_id | |
if des: | |
params['des'] = des | |
if h_max: | |
params['h-max'] = h_max | |
response = requests.get(self.nea_url, params=params) | |
if response.status_code == 200: | |
return response.json() | |
else: | |
print(f"Error: {response.status_code}") | |
return None | |
def get_scout_data(self, nea_comet='NEA', limit=10): | |
"""Get Scout system data for newly discovered objects""" | |
params = {'nea-comet': nea_comet, 'limit': limit} | |
response = requests.get(self.scout_url, params=params) | |
if response.status_code == 200: | |
return response.json() | |
else: | |
print(f"Error: {response.status_code}") | |
return None | |
def format_response(self, data, format_type): | |
"""Format the response data for better readability""" | |
if not data: | |
return None | |
if format_type == 'fireballs': | |
result = [] | |
for fireball in data.get('data', []): | |
entry = { | |
'Date/Time': fireball.get('date'), | |
'Energy (kt)': fireball.get('energy'), | |
'Impact Energy (10^10 J)': fireball.get('impact-e'), | |
'Latitude': fireball.get('lat'), | |
'Longitude': fireball.get('lon'), | |
'Altitude (km)': fireball.get('alt'), | |
'Velocity (km/s)': fireball.get('vel') | |
} | |
result.append(entry) | |
return pd.DataFrame(result) | |
elif format_type == 'close_approaches': | |
result = [] | |
for ca in data.get('data', []): | |
entry = { | |
'Object': ca.get('des'), | |
'Orbit ID': ca.get('orbit_id'), | |
'Time (TDB)': ca.get('cd'), | |
'Nominal Distance (au)': ca.get('dist'), | |
'Minimum Distance (au)': ca.get('dist_min'), | |
'Maximum Distance (au)': ca.get('dist_max'), | |
'Velocity (km/s)': ca.get('v_rel'), | |
'H (mag)': ca.get('h') | |
} | |
result.append(entry) | |
return pd.DataFrame(result) | |
elif format_type == 'nea': | |
result = [] | |
for nea in data.get('data', []): | |
entry = { | |
'Designation': nea.get('des'), | |
'H (mag)': nea.get('h'), | |
'Diameter (km)': nea.get('diameter'), | |
'Orbit Class': nea.get('orbit_class'), | |
'Perihelion (au)': nea.get('q'), | |
'Aphelion (au)': nea.get('ad'), | |
'Inclination (deg)': nea.get('i'), | |
} | |
result.append(entry) | |
return pd.DataFrame(result) | |
elif format_type == 'scout': | |
result = [] | |
for obj in data.get('data', []): | |
entry = { | |
'Object': obj.get('object'), | |
'Rating': obj.get('rating'), | |
'Last Observation': obj.get('last_obs'), | |
'Arc (days)': obj.get('arc'), | |
'Observations': obj.get('n_obs'), | |
'H (mag)': obj.get('h'), | |
'Diameter (m)': obj.get('diameter'), | |
'Close Approach': obj.get('ca_dist_min'), | |
'Velocity (km/s)': obj.get('v_inf') | |
} | |
result.append(entry) | |
return pd.DataFrame(result) | |
return None | |
# Gradio Interface Functions | |
def fetch_fireballs(limit, date_min, energy_min): | |
api = NasaSsdCneosApi() | |
# Convert empty strings to None | |
date_min = date_min if date_min else None | |
energy_min = float(energy_min) if energy_min else None | |
data = api.get_fireballs( | |
limit=int(limit), | |
date_min=date_min, | |
energy_min=energy_min | |
) | |
df = api.format_response(data, 'fireballs') | |
if df is None or df.empty: | |
return "No data available", None | |
# Create world map of fireballs | |
if 'Latitude' in df.columns and 'Longitude' in df.columns: | |
fig = px.scatter_geo(df, | |
lat='Latitude', | |
lon='Longitude', | |
size='Energy (kt)', | |
hover_name='Date/Time', | |
projection='natural earth', | |
title='Fireball Events') | |
return df, fig | |
return df, None | |
def fetch_close_approaches(limit, dist_max, date_min, date_max, h_min, h_max, v_inf_min, v_inf_max): | |
api = NasaSsdCneosApi() | |
# Convert empty strings to None | |
dist_max = float(dist_max) if dist_max else None | |
date_min = date_min if date_min else None | |
date_max = date_max if date_max else None | |
h_min = float(h_min) if h_min else None | |
h_max = float(h_max) if h_max else None | |
v_inf_min = float(v_inf_min) if v_inf_min else None | |
v_inf_max = float(v_inf_max) if v_inf_max else None | |
data = api.get_close_approaches( | |
limit=int(limit), | |
dist_max=dist_max, | |
date_min=date_min, | |
date_max=date_max, | |
h_min=h_min, | |
h_max=h_max, | |
v_inf_min=v_inf_min, | |
v_inf_max=v_inf_max | |
) | |
df = api.format_response(data, 'close_approaches') | |
if df is None or df.empty: | |
return "No data available", None | |
# Create scatter plot of distance vs velocity | |
fig = px.scatter(df, | |
x='Nominal Distance (au)', | |
y='Velocity (km/s)', | |
hover_name='Object', | |
size='H (mag)', | |
color='H (mag)', | |
title='Close Approaches - Distance vs Velocity') | |
return df, fig | |
def fetch_nea_data(des, spk_id, h_max): | |
api = NasaSsdCneosApi() | |
# Convert empty strings to None | |
des = des if des else None | |
spk_id = spk_id if spk_id else None | |
h_max = float(h_max) if h_max else None | |
data = api.get_nea_data( | |
des=des, | |
spk_id=spk_id, | |
h_max=h_max | |
) | |
df = api.format_response(data, 'nea') | |
if df is None or df.empty: | |
return "No data available", None | |
# Create a scatter plot of perihelion vs aphelion colored by inclination | |
if not df.empty and 'Perihelion (au)' in df.columns: | |
fig = px.scatter(df, | |
x='Perihelion (au)', | |
y='Aphelion (au)', | |
hover_name='Designation', | |
color='Inclination (deg)', | |
size='Diameter (km)', | |
title='NEA Orbital Parameters') | |
return df, fig | |
return df, None | |
def fetch_scout_data(limit, nea_comet): | |
api = NasaSsdCneosApi() | |
data = api.get_scout_data( | |
limit=int(limit), | |
nea_comet=nea_comet | |
) | |
df = api.format_response(data, 'scout') | |
if df is None or df.empty: | |
return "No data available", None | |
# Create a scatter plot of diameter vs close approach distance | |
if not df.empty and 'Diameter (m)' in df.columns: | |
fig = px.scatter(df, | |
x='Diameter (m)', | |
y='Close Approach', | |
hover_name='Object', | |
color='Rating', | |
size='Observations', | |
title='Scout Objects - Size vs Close Approach Distance') | |
return df, fig | |
return df, None | |
# Create Gradio interface | |
with gr.Blocks(title="NASA SSD/CNEOS API Explorer") as demo: | |
gr.Markdown("# NASA SSD/CNEOS API Explorer") | |
gr.Markdown("Access data from NASA's Center for Near Earth Object Studies") | |
with gr.Tab("Fireballs"): | |
gr.Markdown("### Fireball Events") | |
gr.Markdown("Get information about recent fireball events detected by sensors.") | |
with gr.Row(): | |
with gr.Column(): | |
fireball_limit = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Limit") | |
fireball_date = gr.Textbox(label="Minimum Date (YYYY-MM-DD)", placeholder="e.g. 2023-01-01") | |
fireball_energy = gr.Textbox(label="Minimum Energy (kt)", placeholder="e.g. 0.5") | |
fireball_submit = gr.Button("Fetch Fireballs") | |
with gr.Column(): | |
fireball_results = gr.DataFrame(label="Fireball Results") | |
fireball_map = gr.Plot(label="Fireball Map") | |
fireball_submit.click(fetch_fireballs, inputs=[fireball_limit, fireball_date, fireball_energy], outputs=[fireball_results, fireball_map]) | |
with gr.Tab("Close Approaches"): | |
gr.Markdown("### Close Approaches") | |
gr.Markdown("Get information about close approaches of near-Earth objects.") | |
with gr.Row(): | |
with gr.Column(): | |
ca_limit = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Limit") | |
ca_dist_max = gr.Textbox(label="Maximum Distance (AU)", placeholder="e.g. 0.05") | |
ca_date_min = gr.Textbox(label="Minimum Date (YYYY-MM-DD)", placeholder="e.g. 2023-01-01") | |
ca_date_max = gr.Textbox(label="Maximum Date (YYYY-MM-DD)", placeholder="e.g. 2023-12-31") | |
ca_h_min = gr.Textbox(label="Minimum H (mag)", placeholder="e.g. 20") | |
ca_h_max = gr.Textbox(label="Maximum H (mag)", placeholder="e.g. 30") | |
ca_v_min = gr.Textbox(label="Minimum Velocity (km/s)", placeholder="e.g. 10") | |
ca_v_max = gr.Textbox(label="Maximum Velocity (km/s)", placeholder="e.g. 30") | |
ca_submit = gr.Button("Fetch Close Approaches") | |
with gr.Column(): | |
ca_results = gr.DataFrame(label="Close Approach Results") | |
ca_plot = gr.Plot(label="Close Approach Plot") | |
ca_submit.click(fetch_close_approaches, | |
inputs=[ca_limit, ca_dist_max, ca_date_min, ca_date_max, ca_h_min, ca_h_max, ca_v_min, ca_v_max], | |
outputs=[ca_results, ca_plot]) | |
with gr.Tab("NEA Data"): | |
gr.Markdown("### Near-Earth Asteroid Data") | |
gr.Markdown("Get information about specific near-Earth asteroids.") | |
with gr.Row(): | |
with gr.Column(): | |
nea_des = gr.Textbox(label="Designation", placeholder="e.g. 2020 SW") | |
nea_spk = gr.Textbox(label="SPK-ID", placeholder="e.g. 54101815") | |
nea_h_max = gr.Textbox(label="Maximum H (mag)", placeholder="e.g. 25") | |
nea_submit = gr.Button("Fetch NEA Data") | |
with gr.Column(): | |
nea_results = gr.DataFrame(label="NEA Results") | |
nea_plot = gr.Plot(label="NEA Orbital Parameters") | |
nea_submit.click(fetch_nea_data, inputs=[nea_des, nea_spk, nea_h_max], outputs=[nea_results, nea_plot]) | |
with gr.Tab("Scout Data"): | |
gr.Markdown("### Scout System Data") | |
gr.Markdown("Get information about newly discovered objects from NASA's Scout system.") | |
with gr.Row(): | |
with gr.Column(): | |
scout_limit = gr.Slider(minimum=1, maximum=100, value=10, step=1, label="Limit") | |
scout_type = gr.Radio(["NEA", "comet"], label="Object Type", value="NEA") | |
scout_submit = gr.Button("Fetch Scout Data") | |
with gr.Column(): | |
scout_results = gr.DataFrame(label="Scout Results") | |
scout_plot = gr.Plot(label="Scout Objects Plot") | |
scout_submit.click(fetch_scout_data, inputs=[scout_limit, scout_type], outputs=[scout_results, scout_plot]) | |
gr.Markdown("### About") | |
gr.Markdown(""" | |
This application provides access to NASA's Solar System Dynamics (SSD) and Center for Near Earth Object Studies (CNEOS) API. | |
Data is retrieved in real-time from NASA's servers. All data is courtesy of NASA/JPL-Caltech. | |
Created by [Your Name] using Gradio and Hugging Face Spaces. | |
""") | |
# Create requirements.txt file | |
requirements = """ | |
gradio>=3.50.0 | |
pandas>=1.5.0 | |
plotly>=5.14.0 | |
requests>=2.28.0 | |
""" | |
with open("requirements.txt", "w") as f: | |
f.write(requirements) | |
if __name__ == "__main__": | |
demo.launch() |