{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Satellites Overhead Visualization Notebook\n", "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." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import plotly.graph_objects as go\n", "import plotly.io as pio\n", "import requests\n", "\n", "pio.renderers.default = \"notebook\"\n", "\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "# Set up the FOV query parameters\n", "julian_date = 2461007.577083 # Example JD\n", "latitude = -33\n", "longitude = -117\n", "elevation = 100 # meters\n", "min_altitude = 60\n", "illuminated_only = \"true\"\n", "min_range = 0\n", "max_range = 1500000\n", "# Make the API request\n", "response = requests.get(\n", " 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}\",\n", " timeout=60\n", ")\n", "data = response.json() " ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Total number of satellites: 102\n" ] } ], "source": [ "# Extract satellite positions\n", "satellites = {}\n", "\n", "for sat_data in data['data']:\n", " sat_key = f\"{sat_data['name']} ({sat_data['norad_id']})\"\n", " \n", " if sat_key not in satellites:\n", " satellites[sat_key] = []\n", " \n", " # Add ra, dec, and julian_date\n", " satellites[sat_key].append([\n", " sat_data['ra'],\n", " sat_data['dec'],\n", " sat_data['julian_date']\n", " ])\n", "\n", "# print total number of satellites\n", "print(f\"Total number of satellites: {len(data['data'])}\")\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig = go.Figure()\n", "ranges = [sat_data['range_km'] for sat_data in data['data']]\n", "min_range = min(ranges)\n", "max_range = max(ranges)\n", "mid_range = 10**(np.log10(min_range) + (np.log10(max_range) - np.log10(min_range))/2)\n", "\n", "\n", "# Add scatter points for satellites\n", "for sat_data in data['data']:\n", " alt = sat_data['altitude']\n", " az = sat_data['azimuth']\n", " range_km = sat_data['range_km']\n", " sat_name = f\"{sat_data['name']} ({sat_data['norad_id']})\"\n", " \n", " r = 90 - alt # Inverse for polar plot\n", " theta = az\n", "\n", " \n", " fig.add_trace(go.Scatterpolar(\n", " r=[90 - sat_data['altitude']],\n", " theta=[sat_data['azimuth']],\n", " mode='markers',\n", " marker=dict(\n", " size=3,\n", " color=[np.log10(range_km)],\n", " cmin=np.log10(min_range), \n", " cmax=np.log10(max_range),\n", " colorscale='Turbo',\n", " showscale=True if range_km == ranges[0] else False, \n", " colorbar=dict(\n", " title=\"Range (km)\",\n", " # Show actual range values at min, middle, and max points\n", " ticktext=[f\"{min_range:.0f}\", \n", " f\"{mid_range:.0f}\", \n", " f\"{max_range:.0f}\"],\n", " tickvals=[np.log10(min_range), \n", " np.log10(mid_range), \n", " np.log10(max_range)],\n", " tickmode=\"array\"\n", " )\n", " ),\n", " hovertext=f\"Name: {sat_name}
\"\n", " f\"Altitude: {sat_data['altitude']:.1f}°
\"\n", " f\"Azimuth: {sat_data['azimuth']:.1f}°
\"\n", " f\"Range: {range_km:.1f} km\",\n", " hoverinfo='text',\n", " showlegend=False \n", " ))\n", "\n", "# Configure layout\n", "fig.update_layout(\n", " polar=dict(\n", " radialaxis=dict(\n", " range=[0, 91],\n", " ticktext=[f\"{90-tick}°\" for tick in [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]], # noqa: E501\n", " tickvals=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90],\n", " tickmode=\"array\",\n", " gridcolor=\"lightgray\",\n", " showgrid=True,\n", " linewidth=0.5,\n", " ),\n", " angularaxis=dict(\n", " ticktext=['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'],\n", " tickvals=np.arange(0, 360, 45),\n", " direction='clockwise',\n", " gridcolor=\"lightgray\",\n", " showgrid=True,\n", " linewidth=0.5,\n", " ),\n", " bgcolor='white',\n", " ),\n", " showlegend=False,\n", " title='All-Sky View with Alt/Az Grid',\n", " width=700,\n", " height=700,\n", " \n", ")\n", "\n", "fig.show()" ] } ], "metadata": { "kernelspec": { "display_name": "env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 2 }