Globe & planet plots#
The globe subsystem renders orthographic views — the sphere shown as a disk. That covers two equally common pictures: the celestial sphere as a hemisphere of sky (the dome above an observatory, a survey hemisphere, one pole’s worth of catalog), and solid bodies — Earth, Moon, planets — seen from outside, at any orientation including a physically tilted, rotating Earth. Under the hood these are SIN-projection WCS frames, so everything from the rest of the package (overlays, regions, HEALPix maps) draws onto them; what this page adds is the orientation machinery, hemisphere-aware plotting, Earth/planet surface features, and globe-specific decorations.
import skyplothelper as sph
import matplotlib.pyplot as plt
Building a globe#
Celestial globe — code in the Feature Gallery.
fig = plt.figure()
# grid=False: let plot_ortho_grid draw the graticule (its front/back styling)
# instead of the builder's default grid, to avoid a faint double graticule.
ax = sph.make_globe_frame(111, center_LONdeg=0, center_LATdeg=23.44, grid=False)
sph.plot_ortho_grid(ax)
make_globe_frame() builds a celestial globe centered
on whatever point of sky you choose (center_LONdeg, center_LATdeg) —
center it on your observatory’s zenith for a “what’s up tonight”
hemisphere, on a celestial pole for a polar-cap view, or on a target
region for a hemisphere of context around it.
For solid bodies, make_planet_frame() is the right
entry point: it selects the geographic longitude convention and the
body-fixed coordinate system in one call (body='earth' by default), so
continents come out un-mirrored. This is the one place the package’s
astro east-left default trips people most — see Core concepts & conventions.
ax = sph.make_planet_frame(111, center_LONdeg=-75, center_LATdeg=20)
plot_ortho_grid() draws the globe graticule with
independent styling for the front and back hemispheres (the dotted
“see-through” back is a nice touch for wireframe looks).
highlight_great_circle() emphasizes any great circle
traced completely around the globe — front solid, far side dashed at a
matched color and weight (the color defaults to the theme’s frame color).
Specify the circle by its pole, two points on it, or an orbital
inclination/node. highlight_meridian_tracer() is
the convenience special case for a meridian (meridian + antimeridian, over
both poles).
Tilted orientations#
A physically tilted globe — the obliquity-inclined, spinning Earth as seen from its orbital plane — is an important special case with dedicated machinery:
euler_to_fits_ortho()converts the physical rotation state —(rotation, obliquity, perspective)Euler angles, the intuitive parameters for a spinning tilted planet — into the(center_lon, center_lat, lonpole)values the frame builders take. Vectorized, which makes rotation sequences (animation frames) one call. Perspective (precession) is only visible with a tilted pole — atobliquity=0it simply adds torotation.quaternion_to_fits_ortho()is the quaternion counterpart (with ascalar_first=order knob); it agrees with the Euler form for the same orientation.TiltedEarthFrameis an astropy coordinate frame with those three Euler angles as attributes — use it as a coordinate overlay to draw a tilted graticule on any frame.make_globe_angles()generates sequences of orientation angles (spin, nutation, precession overn_steps) for animating a rotating, nutating, or precessing globe. Its default output is exactly the(center_lon, center_lat, lonpole)triples the frame builders take, so each step feeds straight intomake_globe_frame()/make_planet_frame()(theeuler_to_fits_orthoconversion happens inside). The bundledobliquitiesandrot_periodstables (axial tilts and spin periods for solar-system bodies, next toplanet_radii) supply physically motivated rates.
Tip
Generating the angle series. For “one clean full rotation (or
precession) over the whole clip,” reach for the whole-animation totals
instead of hand-computed per-step rates: spin_total= / prec_total=
set the total sweep in degrees, and nut_cycles= the number of nutation
oscillations, over all n_steps. Each is endpoint-exclusive, so
spin_total=360 loops seamlessly. (Pass a total or its per-step
*_rate, never both.)
lons, lats, poles = sph.make_globe_angles([0, 24, 45], 120, spin_total=360.)
Precession here drives the perspective (third Euler / psi) angle.
Under skyplothelper’s per-frame frame re-aiming that reads on screen as
the pole precessing around the sky; the same series fed to a
fixed-camera 3-D engine instead spins the body about its already-tilted
pole (the pole itself stays put) — worth knowing if you ever port these
angles to an external 3-D renderer.
Plotting on a globe#
The far side of a globe is the classic trap — a naive
ax.plot(..., transform=...) happily draws right through the sphere. The
globe plotters are hemisphere-aware:
plot_scatter_globe(),plot_line_globe()— points and polylines, far-side portions masked (or restyled).plot_pcolormesh_globe(),plot_contour_globe()— gridded fields on the visible hemisphere.imscatter_globe()(andimscatter()/imscatter_rotated()) — scatter image stamps (icons, thumbnails) at sky positions instead of markers, hemisphere-aware on a globe.zoom=takes an array as readily as a scalar, sizing each stamp individually — the raster counterpart ofscatter(s=...).orthographic_visibility()— the underlying “is this point on the visible side?” test, public for your own logic, withorthographic_forward()/orthographic_inverse()for direct projection math.
Aiming & mirroring image stamps#
imscatter_rotated() can point an icon at a target:
pass aim_at= (a position or SkyCoord; mutually exclusive with rotations=)
together with rest_angle= — the icon’s native boresight, the direction
the un-rotated image already points, in degrees counter-clockwise from
screen-right. The rotation is then solved as aim_angle - rest_angle. This is
the raster twin of the instrument markers’ aiming, and
aim_angles() exposes the same solver (Overlays & annotations).
Measured rest_angle values for the bundled icons live in
examples/data/README.md — the source of truth (the radio dish, for instance,
points at 130°). One asymmetry to note: target_coords= defaults to 'data'
here (matching this function’s own x/y), whereas aim_angles defaults to
'display'.
Two similar-sounding knobs are unrelated. imscatter_rotated’s flip= mirrors
an icon horizontally when the target lies on its far side, so an aimed icon
doesn’t roll past vertical and read upside-down. imscatter_globe instead
mirrors stamps by a hemisphere rule — which side of the globe a point falls
on. Same word, different mechanism. (imscatter_globe also names the
upper-right-icon assumption it has always made, as rest_angle=45.0.)
The spherical-geodesy helpers underneath are general-purpose:
great_circle_distance(),
great_circle_arc(), midpoint(),
initial_bearing(),
destination_point(),
small_circle().
Earth & planet surfaces#
Earth with surface features — code in the Feature Gallery.
Vector features — coastlines, filled land, lakes, rivers, tectonic
plates, and time zones — draw from small data files fetched once per
environment with prepare_earth_data() (Natural Earth
via the optional cartopy extra, plus the Bird 2003 plate polygons; see
Installation). They are not shipped with the package:
sph.prepare_earth_data() # one-time; needs the cartopy extra + network
sph.plot_coastlines(ax)
sph.plot_land(ax, lakes=True) # filled land, lakes punched out as holes
sph.plot_rivers(ax)
sph.plot_tectonic_plates(ax, color="tab:red")
sph.plot_time_zones(ax)
The area features (plot_land(),
plot_lakes(), filled plates) fill through the same
region machinery as add_spherical_polygon(), so they
work on the flat all-sky projections and the custom Robinson/Eckert frames
as well as on the globe. plot_tectonic_plates() takes
fill=True for filled plates — one color, a categorical map, or a
values=-driven choropleth (the general
choropleth() helper does the same for any list of
rings). clip_to_land() /
clip_to_ocean() mask any artist — an image drape, a
scatter — to the coastline.
skyplothelper’s Earth maps aim to make whole-globe views and simple planetary plots look good with little setup; for heavy terrestrial cartography (fine-resolution features, national borders, filled land/ocean at scale, GIS queries) reach for the cartopy backend below.
(load_boundary_data() and
fetch_boundary_data() are the lower-level load / mirror-
download helpers; plot_boundaries_globe() /
plot_boundaries_ortho() draw arbitrary boundary
datasets, and split_segments() breaks polylines at
the visibility horizon.)
Raster maps — any equirectangular texture (NASA Blue Marble, Moon and
Mars mosaics, …) becomes a globe surface via
pseudofits_from_image(), which wraps the image in a
synthetic WCS so the standard reprojection machinery can drape it. It takes
a file path or an array already in memory, so a raster you computed —
a composite, a model map, a blended day/night frame — drapes the same way a
file does, without a round trip through disk.
Nightshade — make_nightshade_blend() blends a
day raster against night (darkened, or a night-lights image) for a given
date. The default blend='elevation' mode computes the actual solar
elevation across the surface, giving a physical terminator with twilight
falloff; a softer cosmetic 'gaussian' mode is available when you want
a stylized look.
shaded = sph.make_nightshade_blend(day_rgb, date="2026-06-21 18:00")
The cartopy backend#
For terrestrial maps that want cartopy’s feature stack (coastlines,
borders, land/ocean fills, the full projection library), build a cartopy
GeoAxes instead of a WCS globe: make_cartopy_frame()
and the one-call cartopy_figure(), with
list_cartopy_projections() enumerating the options.
Like make_planet_frame(), these default to the
geographic (east-right) convention. (Requires the cartopy extra; the
trio is listed in the utilities API reference.)
Decorations & insets#
Globe-specific furniture: add_compass_rose() (a fixed
N/E/S/W rose in screen space) versus
add_surface_compass() (planted on the surface at a
(lon, lat), so it foreshortens with the globe — style= picks a two-tone
'star' rose, a connected 'arrow' N+E frame, or geodesic 'lines'
arms), add_checkered_border() (surveyor-style
alternating border), add_pole_rod() (the axis rod
through the poles, for orientation at a glance), and
distance scale bars — add_scale_bar() with
_cylindrical and _curved_parallel variants that follow a parallel at
the chosen latitude, in real distance units via the body radius
(planet_radii covers the solar system).
Inset axes connect a globe to a zoom:
inset = sph.reproject_inset_axes(ax, [0.65, 0.05, 0.3, 0.3],
projection="TAN", center=(-80, 25), size=8)
sph.mark_inset_axes(ax, inset)
sph.connect_inset_axes(ax, inset)
reproject_inset_axes() builds a reprojected child
frame (different projection, different scale) and inherits the parent’s
on-screen longitude direction by default, so a geographic parent never
gets a mirrored inset. The connector lines accept a curvature control for
when straight connectors would cut through the marked region.
Pitfalls#
Mirrored continents → you built a celestial frame for terrestrial data; use
make_planet_frame()(see Core concepts & conventions).Tracks drawn through the planet → raw matplotlib calls aren’t hemisphere-aware; use the
plot_*_globefamily or mask withorthographic_visibility().plot_coastlines(orplot_land/plot_tectonic_plates/ …) complaining about missing data → runprepare_earth_data()once per environment to fetch and cache the vector Earth data (needs thecartopyextra).Scale bar length looks wrong on another body → pass the body so the radius lookup matches (
planet_radiikeys); a Mars km is not an Earth degree.
Baseline networks between ground stations
(plot_baselines()) and co-visibility regions are
covered with the other station-network tools in Vectors & sky kinematics. Full
listing: API reference.
See also: Frames & projections — globe frames are SIN-projection WCSAxes, so the centering/aspect rules and the rest of the frame toolkit apply here too.
Tutorials: Globe & planet plotting (tilted-Earth orientation, raster planet maps, Earth features, nightshade, and globe decorations); Insets & zoom axes for the inset/zoom machinery; and Animations for rotating globes and the advancing terminator.