3-D Spacecraft Configuration Visualizer

plot_spacecraft_3d renders an interactive, rotatable 3-D model of a spacecraft directly from its MissionConfig. The figure is produced with Plotly and can be rotated, zoomed, and panned in any browser or Jupyter notebook without running a full DITL simulation.

Features

  • Spacecraft bus — lit, solid-shaded box with configurable dimensions.

  • Telescope assembly — cylindrical baffle tube with aperture ring, mid-tube baffle rings, and secondary mirror housing. Sized automatically from optics.aperture_m and optics.tube_length_m.

  • Solar panels — deep-blue solar cell faces on a silver frame. Uses PanelGeometry when configured, otherwise places panels on the bus face whose outward normal best matches the panel normal vector. Panel area is estimated from max_power.

  • Radiators — white/MLI panels placed on the bus face matching orientation.normal, sized by width_m × height_m.

  • Star trackers — small prism bodies with a coloured aperture face, one per configured tracker. Each gets a distinct boresight-arrow colour.

  • Body-frame axes — +X / +Y / +Z triad with labelled arrows (red, green, blue).

  • Normal / boresight arrows — outward-normal arrows for solar panels and radiators; boresight arrows for the telescope and each star tracker.

Coordinate system

All geometry is expressed in the spacecraft body frame:

Axis

Meaning

+X

Boresight / telescope pointing direction

+Y

Spacecraft “up”

+Z

Completes the right-handed system

Quick start

from conops.config import MissionConfig
from conops.visualization import plot_spacecraft_3d

config = MissionConfig.from_json_file("examples/example_config.json")
fig = plot_spacecraft_3d(config)
fig.show()

No simulation run is needed — the visualizer reads geometry directly from the configuration.

Usage examples

Minimal default spacecraft

from conops.config import MissionConfig
from conops.visualization import plot_spacecraft_3d

# Default config gives a bus, one solar panel, one radiator, and one star tracker
fig = plot_spacecraft_3d(MissionConfig())
fig.show()

Custom Ritchey-Chrétien telescope

from conops.config import MissionConfig
from conops.config.instrument import Telescope, TelescopeConfig, TelescopeType, Payload
from conops.config.solar_panel import SolarPanel, SolarPanelSet, create_solar_panel_vector
from conops.visualization import plot_spacecraft_3d

config = MissionConfig(
    payload=Payload(instruments=[
        Telescope(
            name="Primary",
            boresight=(1.0, 0.0, 0.0),
            optics=TelescopeConfig(
                aperture_m=0.5,
                focal_length_m=3.5,
                tube_length_m=1.6,
                telescope_type=TelescopeType.RITCHEY_CHRETIEN,
            ),
        )
    ]),
    solar_panel=SolarPanelSet(panels=[
        SolarPanel(name="Panel +Y", normal=create_solar_panel_vector("sidemount"),         max_power=1200.0),
        SolarPanel(name="Panel -Y", normal=create_solar_panel_vector("sidemount", cant_z=180.0), max_power=1200.0),
    ]),
)

fig = plot_spacecraft_3d(config, title="RC Telescope — Dual Wing Config")
fig.show()

Overriding the bus box size

# bus_half_dims = (half_X, half_Y, half_Z) in metres
fig = plot_spacecraft_3d(config, bus_half_dims=(1.2, 0.65, 0.65))
fig.show()

Hiding normal vectors or axes

# Clean view without arrows
fig = plot_spacecraft_3d(config, show_normals=False, show_axes=False)
fig.show()

Embedding in a Jupyter notebook

# The figure is a standard go.Figure — display inline with:
fig = plot_spacecraft_3d(config)
fig  # Jupyter evaluates this cell and renders the Plotly widget

Saving to HTML

fig = plot_spacecraft_3d(config)
fig.write_html("spacecraft_model.html")

Visual elements reference

Element

Colour

Source in config

Spacecraft bus

Silver-gray

bus_half_dims parameter (default 1.0 × 0.55 × 0.55 m)

Telescope tube

Dark gunmetal

payload.instruments (instrument_type = "Telescope")

Aperture / baffle rings

Gold

optics.aperture_m, optics.tube_length_m

Solar cell faces

Deep blue

solar_panel.panels[*].normal, PanelGeometry

Solar panel frames

Silver

Derived from panel geometry

Radiators

White / MLI

spacecraft_bus.radiators.radiators[*]

Star tracker body

Dark gray

spacecraft_bus.star_trackers.star_trackers[*]

Star tracker aperture

Per-tracker colour

One of orange / hotpink / cyan / limegreen / gold / violet

+X axis

Red

Hard-coded body frame

+Y axis

Limegreen

Hard-coded body frame

+Z axis

Dodgerblue

Hard-coded body frame

Panel / radiator normals

Yellow

normal / orientation.normal

Telescope boresight

Cyan

boresight

Star tracker boresights

Per-tracker colour

orientation.boresight

Panel placement rules

When a PanelGeometry is attached to a solar panel or radiator, its center_m, u, v, width_m, and height_m fields are used directly.

When no PanelGeometry is set the visualizer falls back to automatic face placement:

  1. Dot-product the component normal against the six bus face normals.

  2. Select the face with the largest dot product.

  3. Place the component centre just outside that face (gap is component-specific; e.g. 20 mm for solar panels and 5 mm for radiators) and orient the panel spanning directions perpendicular to the face normal.

Solar panel size is estimated from max_power assuming 150 W/m² (solar constant × typical conversion efficiency). Radiator size comes directly from width_m and height_m.

API reference

See also

  • Mission Configuration — all geometric configuration fields in detail.

  • Visualization — overview of all COASTSim visualization utilities.

  • Sky Pointing Visualization — interactive sky-pointing globe.

  • conops.visualization.plot_sky_pointing_globe() — celestial-sphere globe driven by a completed DITL simulation.