Source code for opengnc.visualization.ground_track


import numpy as np
import plotly.graph_objects as go


[docs] def plot_ground_track( latitudes: np.ndarray | list[float], longitudes: np.ndarray | list[float], times: np.ndarray | list[float] | None = None, title: str = "Satellite Ground Track" ) -> go.Figure: """ 2D Sub-Satellite Point (SSP) Visualization. Projects the spacecraft trajectory onto a 2D equirectangular map tracking latitude and longitude evolution over time. Parameters ---------- latitudes : Union[np.ndarray, List[float]] Geodetic or geocentric latitudes (deg). Range: $[-90, 90]$. longitudes : Union[np.ndarray, List[float]] Geodetic or geocentric longitudes (deg). Range: $[-180, 180]$. times : Optional[Union[np.ndarray, List[float]]], optional Simulation timestamps (s) for hover metadata. title : str, optional Plot main heading. Returns ------- plotly.graph_objects.Figure Interactive 2D map plot. Raises ------ ValueError If coordinate arrays have mismatched lengths. """ lats = np.asarray(latitudes) lons = np.asarray(longitudes) if lats.shape != lons.shape: raise ValueError("Latitudes and longitudes must have the same length.") fig = go.Figure() # 1. Build Hover Metadata hover_text = [] if times is not None: t_vals = np.asarray(times) for t, lat, lon in zip(t_vals, lats, lons): hover_text.append(f"T: {t:.1f}s<br>Lat: {lat:.2f}\u00b0<br>Lon: {lon:.2f}\u00b0") else: for lat, lon in zip(lats, lons): hover_text.append(f"Lat: {lat:.2f}\u00b0<br>Lon: {lon:.2f}\u00b0") # 2. Main Ground Track Trace fig.add_trace( go.Scattergeo( lat=lats, lon=lons, mode="lines+markers", line=dict(width=2, color="darkorange"), marker=dict(size=4, color="darkorange", opacity=0.8), hovertext=hover_text, hoverinfo="text", name="Ground Track", ) ) # 3. Markers fig.add_trace( go.Scattergeo( lat=[lats[0]], lon=[lons[0]], mode="markers", marker=dict(size=8, color="green", symbol="circle"), name="Start", ) ) fig.add_trace( go.Scattergeo( lat=[lats[-1]], lon=[lons[-1]], mode="markers", marker=dict(size=8, color="red", symbol="square"), name="End", ) ) # 4. Map Layout configuration fig.update_layout( title=title, geo=dict( showland=True, showcoastlines=True, projection_type="equirectangular", coastlinecolor="gray", landcolor="white", lakecolor="lightblue", rivercolor="lightblue", showocean=True, oceancolor="aliceblue", lataxis=dict(range=[-90, 90], showgrid=True, gridcolor="lightgray"), lonaxis=dict(range=[-180, 180], showgrid=True, gridcolor="lightgray"), ), margin=dict(r=0, l=0, b=0, t=40), ) return fig