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()