Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -7,14 +7,12 @@ import traceback
|
|
7 |
import plotly.express as px
|
8 |
import plotly.graph_objects as go
|
9 |
|
10 |
-
# Updated NASA API client with proper endpoints and data parsing
|
11 |
-
import requests
|
12 |
-
import pandas as pd
|
13 |
-
|
14 |
class NasaSsdCneosApi:
|
15 |
def __init__(self):
|
16 |
self.fireball_url = "https://ssd-api.jpl.nasa.gov/fireball.api"
|
17 |
self.ca_url = "https://ssd-api.jpl.nasa.gov/cad.api"
|
|
|
|
|
18 |
|
19 |
def get_fireballs(self, limit=10, date_min=None, energy_min=None):
|
20 |
try:
|
@@ -33,8 +31,8 @@ class NasaSsdCneosApi:
|
|
33 |
return None
|
34 |
|
35 |
def get_close_approaches(self, dist_max=None, date_min=None, date_max=None,
|
36 |
-
|
37 |
-
|
38 |
try:
|
39 |
params = {'limit': limit, 'dist-max': dist_max, 'date-min': date_min,
|
40 |
'date-max': date_max, 'h-min': h_min, 'h-max': h_max,
|
@@ -49,6 +47,46 @@ class NasaSsdCneosApi:
|
|
49 |
traceback.print_exc()
|
50 |
return None
|
51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
def format_response(self, data, format_type):
|
53 |
try:
|
54 |
if not data:
|
@@ -77,6 +115,29 @@ class NasaSsdCneosApi:
|
|
77 |
'dist_max': 'Maximum Distance (au)', 'v_rel': 'Velocity (km/s)',
|
78 |
'h': 'H (mag)'
|
79 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
return df
|
82 |
except Exception as e:
|
@@ -85,7 +146,6 @@ class NasaSsdCneosApi:
|
|
85 |
return None
|
86 |
|
87 |
|
88 |
-
|
89 |
# Gradio Interface Functions
|
90 |
|
91 |
def fetch_fireballs(limit, date_min, energy_min):
|
@@ -176,13 +236,13 @@ def fetch_nea_data(des, spk_id, h_max):
|
|
176 |
return "No data available", None
|
177 |
|
178 |
# Create a scatter plot of perihelion vs aphelion colored by inclination
|
179 |
-
if not df.empty and 'Perihelion (au)' in df.columns:
|
180 |
fig = px.scatter(df,
|
181 |
x='Perihelion (au)',
|
182 |
y='Aphelion (au)',
|
183 |
-
hover_name='Designation',
|
184 |
-
color='Inclination (deg)',
|
185 |
-
size='Diameter (km)',
|
186 |
title='NEA Orbital Parameters')
|
187 |
|
188 |
return df, fig
|
@@ -201,15 +261,22 @@ def fetch_scout_data(limit, nea_comet):
|
|
201 |
if df is None or df.empty:
|
202 |
return "No data available", None
|
203 |
|
204 |
-
# Create a scatter plot
|
205 |
-
if not df.empty
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
fig = px.scatter(df,
|
207 |
-
x=
|
208 |
-
y=
|
209 |
-
hover_name=
|
210 |
-
color=
|
211 |
-
size=
|
212 |
-
title='Scout Objects
|
213 |
|
214 |
return df, fig
|
215 |
|
|
|
7 |
import plotly.express as px
|
8 |
import plotly.graph_objects as go
|
9 |
|
|
|
|
|
|
|
|
|
10 |
class NasaSsdCneosApi:
|
11 |
def __init__(self):
|
12 |
self.fireball_url = "https://ssd-api.jpl.nasa.gov/fireball.api"
|
13 |
self.ca_url = "https://ssd-api.jpl.nasa.gov/cad.api"
|
14 |
+
self.nea_url = "https://ssd-api.jpl.nasa.gov/sbdb_query.api"
|
15 |
+
self.scout_url = "https://ssd-api.jpl.nasa.gov/scout.api"
|
16 |
|
17 |
def get_fireballs(self, limit=10, date_min=None, energy_min=None):
|
18 |
try:
|
|
|
31 |
return None
|
32 |
|
33 |
def get_close_approaches(self, dist_max=None, date_min=None, date_max=None,
|
34 |
+
h_min=None, h_max=None, v_inf_min=None, v_inf_max=None,
|
35 |
+
limit=10):
|
36 |
try:
|
37 |
params = {'limit': limit, 'dist-max': dist_max, 'date-min': date_min,
|
38 |
'date-max': date_max, 'h-min': h_min, 'h-max': h_max,
|
|
|
47 |
traceback.print_exc()
|
48 |
return None
|
49 |
|
50 |
+
def get_nea_data(self, des=None, spk_id=None, h_max=None):
|
51 |
+
try:
|
52 |
+
# Build query parameter for NEAs - select asteroid with NEA flag
|
53 |
+
query_params = {
|
54 |
+
'sb-nea': 'true' # Filter for Near-Earth Asteroids
|
55 |
+
}
|
56 |
+
|
57 |
+
if des:
|
58 |
+
query_params['sb-spk'] = des
|
59 |
+
if spk_id:
|
60 |
+
query_params['sb-spkid'] = spk_id
|
61 |
+
if h_max:
|
62 |
+
query_params['sb-h-max'] = h_max
|
63 |
+
|
64 |
+
# Add fields to return
|
65 |
+
query_params['fields'] = 'spkid,full_name,pdes,neo,H,G,diameter,extent,albedo,rot_per,GM,BV,UB,IR,spec_B,spec_T,H_sigma,diameter_sigma,orbit_id,epoch,epoch_mjd,epoch_cal,a,e,i,om,w,ma,ad,n,tp,tp_cal,per,per_y,q,moid,moid_ld,moid_jup'
|
66 |
+
query_params['limit'] = 100 # Set a reasonable limit
|
67 |
+
|
68 |
+
response = requests.get(self.nea_url, params=query_params)
|
69 |
+
response.raise_for_status()
|
70 |
+
return response.json()
|
71 |
+
except Exception as e:
|
72 |
+
print("NEA API Error:", e)
|
73 |
+
traceback.print_exc()
|
74 |
+
return None
|
75 |
+
|
76 |
+
def get_scout_data(self, limit=10, nea_comet="NEA"):
|
77 |
+
try:
|
78 |
+
params = {'limit': limit}
|
79 |
+
if nea_comet:
|
80 |
+
params['nea-comet'] = nea_comet.lower()
|
81 |
+
|
82 |
+
response = requests.get(self.scout_url, params=params)
|
83 |
+
response.raise_for_status()
|
84 |
+
return response.json()
|
85 |
+
except Exception as e:
|
86 |
+
print("Scout API Error:", e)
|
87 |
+
traceback.print_exc()
|
88 |
+
return None
|
89 |
+
|
90 |
def format_response(self, data, format_type):
|
91 |
try:
|
92 |
if not data:
|
|
|
115 |
'dist_max': 'Maximum Distance (au)', 'v_rel': 'Velocity (km/s)',
|
116 |
'h': 'H (mag)'
|
117 |
})
|
118 |
+
|
119 |
+
elif format_type == 'nea':
|
120 |
+
name_columns = {
|
121 |
+
'full_name': 'Full Name', 'pdes': 'Designation',
|
122 |
+
'H': 'Absolute Magnitude (mag)', 'diameter': 'Diameter (km)',
|
123 |
+
'q': 'Perihelion (au)', 'ad': 'Aphelion (au)',
|
124 |
+
'i': 'Inclination (deg)', 'e': 'Eccentricity',
|
125 |
+
'moid': 'MOID (au)', 'moid_ld': 'MOID (LD)'
|
126 |
+
}
|
127 |
+
# Use only columns that exist in the dataframe
|
128 |
+
valid_columns = {k: v for k, v in name_columns.items() if k in df.columns}
|
129 |
+
return df.rename(columns=valid_columns)
|
130 |
+
|
131 |
+
elif format_type == 'scout':
|
132 |
+
# Handle Scout API response - column names may vary
|
133 |
+
# Adjust these column mappings based on actual response structure
|
134 |
+
if 'score' in df.columns:
|
135 |
+
df = df.rename(columns={
|
136 |
+
'object': 'Object', 'score': 'Rating',
|
137 |
+
'diameter': 'Diameter (m)', 'ca_dist': 'Close Approach',
|
138 |
+
'nobs': 'Observations'
|
139 |
+
})
|
140 |
+
return df
|
141 |
|
142 |
return df
|
143 |
except Exception as e:
|
|
|
146 |
return None
|
147 |
|
148 |
|
|
|
149 |
# Gradio Interface Functions
|
150 |
|
151 |
def fetch_fireballs(limit, date_min, energy_min):
|
|
|
236 |
return "No data available", None
|
237 |
|
238 |
# Create a scatter plot of perihelion vs aphelion colored by inclination
|
239 |
+
if not df.empty and 'Perihelion (au)' in df.columns and 'Aphelion (au)' in df.columns:
|
240 |
fig = px.scatter(df,
|
241 |
x='Perihelion (au)',
|
242 |
y='Aphelion (au)',
|
243 |
+
hover_name='Designation' if 'Designation' in df.columns else None,
|
244 |
+
color='Inclination (deg)' if 'Inclination (deg)' in df.columns else None,
|
245 |
+
size='Diameter (km)' if 'Diameter (km)' in df.columns else None,
|
246 |
title='NEA Orbital Parameters')
|
247 |
|
248 |
return df, fig
|
|
|
261 |
if df is None or df.empty:
|
262 |
return "No data available", None
|
263 |
|
264 |
+
# Create a scatter plot based on available columns
|
265 |
+
if not df.empty:
|
266 |
+
# Use columns that are available in the dataframe
|
267 |
+
x_col = 'Diameter (m)' if 'Diameter (m)' in df.columns else df.columns[0]
|
268 |
+
y_col = 'Close Approach' if 'Close Approach' in df.columns else df.columns[1]
|
269 |
+
hover_col = 'Object' if 'Object' in df.columns else None
|
270 |
+
color_col = 'Rating' if 'Rating' in df.columns else None
|
271 |
+
size_col = 'Observations' if 'Observations' in df.columns else None
|
272 |
+
|
273 |
fig = px.scatter(df,
|
274 |
+
x=x_col,
|
275 |
+
y=y_col,
|
276 |
+
hover_name=hover_col,
|
277 |
+
color=color_col,
|
278 |
+
size=size_col,
|
279 |
+
title='Scout Objects')
|
280 |
|
281 |
return df, fig
|
282 |
|