Satellites Overhead Visualization Notebook
This Jupyter Notebook is meant to illustrate how the SatChecker FOV API (https://satchecker.cps.iau.org/fov) can be used with Python/Plotly to visualize all satellites overhead a given location.
[36]:
import numpy as np
import plotly.graph_objects as go
import plotly.io as pio
import requests
pio.renderers.default = "notebook"
%matplotlib inline
[37]:
# Set up the FOV query parameters
julian_date = 2460613.194803 # Example JD
latitude = -33
longitude = -117
elevation = 100 # meters
min_altitude = 0
illuminated_only = "false"
min_range = 0
max_range = 1500000
# Make the API request
response = requests.get(
f"https://dev.satchecker.cps.iau.noirlab.edu/fov/satellites-above-horizon/?latitude={latitude}&longitude={longitude}&elevation={elevation}&julian_date={julian_date}&illuminated_only={illuminated_only}&min_altitude={min_altitude}&min_range={min_range}&max_range={max_range}",
timeout=60
)
data = response.json()
[38]:
# Extract satellite positions
satellites = {}
for sat_data in data['data']:
sat_key = f"{sat_data['name']} ({sat_data['norad_id']})"
if sat_key not in satellites:
satellites[sat_key] = []
# Add ra, dec, and julian_date
satellites[sat_key].append([
sat_data['ra'],
sat_data['dec'],
sat_data['julian_date']
])
# print total number of satellites
print(f"Total number of satellites: {len(data['data'])}")
Total number of satellites: 2684
[39]:
fig = go.Figure()
ranges = [sat_data['range_km'] for sat_data in data['data']]
min_range = min(ranges)
max_range = max(ranges)
mid_range = 10**(np.log10(min_range) + (np.log10(max_range) - np.log10(min_range))/2)
# Add scatter points for satellites
for sat_data in data['data']:
alt = sat_data['altitude']
az = sat_data['azimuth']
range_km = sat_data['range_km']
sat_name = f"{sat_data['name']} ({sat_data['norad_id']})"
r = 90 - alt # Inverse for polar plot
theta = az
fig.add_trace(go.Scatterpolar(
r=[90 - sat_data['altitude']],
theta=[sat_data['azimuth']],
mode='markers',
marker=dict(
size=3,
color=[np.log10(range_km)],
cmin=np.log10(min_range),
cmax=np.log10(max_range),
colorscale='Turbo',
showscale=True if range_km == ranges[0] else False,
colorbar=dict(
title="Range (km)",
# Show actual range values at min, middle, and max points
ticktext=[f"{min_range:.0f}",
f"{mid_range:.0f}",
f"{max_range:.0f}"],
tickvals=[np.log10(min_range),
np.log10(mid_range),
np.log10(max_range)],
tickmode="array"
)
),
hovertext=f"Name: {sat_name}<br>"
f"Altitude: {sat_data['altitude']:.1f}°<br>"
f"Azimuth: {sat_data['azimuth']:.1f}°<br>"
f"Range: {range_km:.1f} km",
hoverinfo='text',
showlegend=False
))
# Configure layout
fig.update_layout(
polar=dict(
radialaxis=dict(
range=[0, 91],
ticktext=[f"{90-tick}°" for tick in [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]], # noqa: E501
tickvals=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90],
tickmode="array",
gridcolor="lightgray",
showgrid=True,
linewidth=0.5,
),
angularaxis=dict(
ticktext=['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'],
tickvals=np.arange(0, 360, 45),
direction='clockwise',
gridcolor="lightgray",
showgrid=True,
linewidth=0.5,
),
bgcolor='white',
),
showlegend=False,
title='All-Sky View with Alt/Az Grid',
width=700,
height=700,
)
fig.show()