Skip to content

Plotting & Visualization

Brahe provides quick and convenient plotting functions for visualizing orbital trajectories, ground tracks, access windows, and other astrodynamics data. The plotting module is designed to make it easy to generate publication-quality figures with minimal code while offering flexibility for customization.

Experimental API

The plotting API in brahe is currently experimental and may undergo significant changes in future releases. While we strive to maintain backward compatibility, functions, parameters, or behaviors may change as we refine the plotting capabilities based on user feedback and evolving best practices in data visualization. These changes may occur in minor or patch releases.

Dual Backend System

All plotting functions in brahe support two rendering backends, allowing you to choose the best tool for your workflow:

Matplotlib Backend

The matplotlib backend generates static, publication-ready figures. This is the default backend and is ideal for academic papers and technical reports.

1
2
3
4
5
6
7
8
import brahe as bh

# Use matplotlib backend (default)
fig = bh.plot_groundtrack(
    trajectories=[{"trajectory": traj}],
    backend="matplotlib"
)
fig.savefig("groundtrack.png", dpi=300)

Science Plots Styling

Brahe integrates with the scienceplots package to provide publication-quality matplotlib styling. When scienceplots is installed, brahe automatically applies clean, professional styling to matplotlib plots.

To enable science plots styling either install brahe with all optional dependencies:

pip install brahe[all]

Or install scienceplots separately:

pip install scienceplots

To take full advantage of science plots styling, you can need a \(\LaTeX\) installation on your system, as scienceplots uses LaTeX for rendering text in plots. See the scienceplots documentation for guidance on setting up LaTeX.

If scienceplots is not installed, brahe falls back to standard matplotlib styling.

Plotly Backend

The plotly backend creates interactive HTML figures that can be explored in a web browser. This backend is perfect for interactive exploration of data or sharing results via web pages or notebooks.

1
2
3
4
5
6
7
8
9
import brahe as bh

# Use plotly backend for interactive plots
fig = bh.plot_groundtrack(
    trajectories=[{"trajectory": traj}],
    backend="plotly"
)
fig.write_html("groundtrack.html")
fig.show()  # Opens in browser

Both backends use the same function signatures and parameters, making it trivial to switch between static and interactive outputs.

Available Plot Types

Brahe provides specialized plotting functions for common astrodynamics visualization tasks:

Ground Track Plots

Visualize satellite ground tracks on a world map with ground stations and communication coverage zones.

1
2
3
4
fig = bh.plot_groundtrack(
    trajectories=[{"trajectory": orbit_traj}],
    ground_stations=[{"stations": [station1, station2]}]
)

3D Trajectory Plots

Visualize orbital trajectories in 3D space with an optional Earth sphere.

1
2
3
4
fig = bh.plot_trajectory_3d(
    [{"trajectory": traj, "label": "LEO Orbit"}],
    show_earth=True
)

Access Geometry Plots

Visualize satellite visibility from ground stations using polar plots (azimuth/elevation) or elevation profiles over time.

1
2
3
4
5
# Polar plot showing satellite path in sky
fig = bh.plot_access_polar(access_window)

# Elevation angle over time
fig = bh.plot_access_elevation(access_window)

Orbital Element Plots

Track how orbital elements evolve over time in both Cartesian and Keplerian representations.

1
2
3
4
5
# Plot position and velocity components
fig = bh.plot_cartesian_trajectory([{"trajectory": traj}])

# Plot Keplerian elements (a, e, i, Ω, ω, ν)
fig = bh.plot_keplerian_trajectory([{"trajectory": traj}])

Gabbard Diagrams

Analyze debris clouds or satellite constellations by plotting orbital period versus apogee/perigee altitude.

1
2
3
4
fig = bh.plot_gabbard_diagram(
    propagators=[prop1, prop2, prop3],
    epoch=epoch
)

Common Features

All plotting functions share consistent design patterns:

  • Grouped plotting: Plot multiple trajectories, stations, or objects with different colors and labels
  • Flexible inputs: Accept propagators, trajectories, or raw numpy arrays
  • Unit conversion: Automatic handling of meters/kilometers, radians/degrees, etc.
  • Time filtering: Optional time range filtering for all trajectory plots
  • Customization: Control colors, line widths, markers, and other visual properties

Quick Start Example

This example shows how to create a simple LEO orbit and visualize it in 3D. It demonstrates the core plotting workflow: define an orbit, propagate it, and visualize the results. Both plotly and matplotlib backends are shown.

Matplotlib 3D Visualization Limitations

The matplotlib 3D backend does not have a true 3D perspective camera model. Instead is uses a 2D layering system where entire objects (e.g., the entire orbit line, the entire sphere surface) are drawn one on top of the other based on a single, fixed zorder value.

This can lead to visual artifacts where parts of objects that should be behind other objects are incorrectly drawn in front. For example, the far side of an orbit may appear in front of the Earth sphere.

Interactive Plot (Plotly)

Plot Source
quickstart_example_plotly.py
OUTDIR = pathlib.Path(os.getenv("BRAHE_FIGURE_OUTPUT_DIR", "./docs/figures/"))
os.makedirs(OUTDIR, exist_ok=True)

# Initialize EOP data
bh.initialize_eop()

# Create a simple LEO orbit
epoch = bh.Epoch.from_datetime(2025, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)
oe = np.array([bh.R_EARTH + 500e3, 0.01, 97.8, 0.0, 0.0, 0.0])

# Create propagator and generate trajectory
prop = bh.KeplerianPropagator.from_keplerian(epoch, oe, bh.AngleFormat.DEGREES, 5.0)
prop.propagate_to(epoch + bh.orbital_period(oe[0]))
traj = prop.trajectory

# Create an interactive 3D plot
fig = bh.plot_trajectory_3d(
    [{"trajectory": traj, "color": "red", "label": "LEO"}],
    show_earth=True,
    backend="plotly",
)

# Save themed HTML files
light_path, dark_path = save_themed_html(fig, OUTDIR / SCRIPT_NAME)
print(f"✓ Generated {light_path}")
print(f"✓ Generated {dark_path}")

Static Plot (Matplotlib)

Quick Start Example Quick Start Example
Plot Source
quickstart_example_matplotlib.py
import brahe as bh
import numpy as np
import matplotlib.pyplot as plt

# Initialize EOP data
bh.initialize_eop()

# Create a simple LEO orbit
epoch = bh.Epoch.from_datetime(2025, 1, 1, 0, 0, 0.0, 0.0, bh.TimeSystem.UTC)
oe = np.array([bh.R_EARTH + 500e3, 0.01, 97.8, 0.0, 0.0, 0.0])
state = bh.state_koe_to_eci(oe, bh.AngleFormat.DEGREES)

# Create propagator and generate trajectory
prop = bh.KeplerianPropagator.from_eci(epoch, state, 60.0)
prop.propagate_to(epoch + bh.orbital_period(oe[0]))
traj = prop.trajectory

# Create a 3D plot in light mode
fig = bh.plot_trajectory_3d(
    [{"trajectory": traj, "color": "red", "label": "LEO"}],
    show_earth=True,
    backend="matplotlib",
)

# Save light mode figure
fig.savefig(
    "docs/figures/plot_quickstart_example_matplotlib_light.svg",
    dpi=300,
    bbox_inches="tight",
)
print(
    "Quick start example plot (matplotlib, light mode) saved to: docs/figures/plot_quickstart_example_matplotlib_light.svg"
)
plt.close(fig)

# Create a 3D plot in dark mode
with plt.style.context("dark_background"):
    fig = bh.plot_trajectory_3d(
        [{"trajectory": traj, "color": "red", "label": "LEO"}],
        show_earth=True,
        backend="matplotlib",
    )

    # Set background color to match Plotly dark theme
    fig.patch.set_facecolor("#1c1e24")
    for ax in fig.get_axes():
        ax.set_facecolor("#1c1e24")

    # Save dark mode figure
    fig.savefig(
        "docs/figures/plot_quickstart_example_matplotlib_dark.svg",
        dpi=300,
        bbox_inches="tight",
    )
    print(
        "Quick start example plot (matplotlib, dark mode) saved to: docs/figures/plot_quickstart_example_matplotlib_dark.svg"
    )
    plt.close(fig)

See Also