Files
gh-k-dense-ai-claude-scient…/skills/astropy/references/coordinates.md
2025-11-30 08:30:10 +08:00

6.9 KiB

Astronomical Coordinates (astropy.coordinates)

The astropy.coordinates package provides tools for representing celestial coordinates and transforming between different coordinate systems.

Creating Coordinates with SkyCoord

The high-level SkyCoord class is the recommended interface:

from astropy import units as u
from astropy.coordinates import SkyCoord

# Decimal degrees
c = SkyCoord(ra=10.625*u.degree, dec=41.2*u.degree, frame='icrs')

# Sexagesimal strings
c = SkyCoord(ra='00h42m30s', dec='+41d12m00s', frame='icrs')

# Mixed formats
c = SkyCoord('00h42.5m +41d12m', unit=(u.hourangle, u.deg))

# Galactic coordinates
c = SkyCoord(l=120.5*u.degree, b=-23.4*u.degree, frame='galactic')

Array Coordinates

Process multiple coordinates efficiently using arrays:

# Create array of coordinates
coords = SkyCoord(ra=[10, 11, 12]*u.degree,
                  dec=[41, -5, 42]*u.degree)

# Access individual elements
coords[0]
coords[1:3]

# Array operations
coords.shape
len(coords)

Accessing Components

c = SkyCoord(ra=10.68*u.degree, dec=41.27*u.degree, frame='icrs')

# Access coordinates
c.ra        # <Longitude 10.68 deg>
c.dec       # <Latitude 41.27 deg>
c.ra.hour   # Convert to hours
c.ra.hms    # Hours, minutes, seconds tuple
c.dec.dms   # Degrees, arcminutes, arcseconds tuple

String Formatting

c.to_string('decimal')      # '10.68 41.27'
c.to_string('dms')          # '10d40m48s 41d16m12s'
c.to_string('hmsdms')       # '00h42m43.2s +41d16m12s'

# Custom formatting
c.ra.to_string(unit=u.hour, sep=':', precision=2)

Coordinate Transformations

Transform between reference frames:

c_icrs = SkyCoord(ra=10.68*u.degree, dec=41.27*u.degree, frame='icrs')

# Simple transformations (as attributes)
c_galactic = c_icrs.galactic
c_fk5 = c_icrs.fk5
c_fk4 = c_icrs.fk4

# Explicit transformations
c_icrs.transform_to('galactic')
c_icrs.transform_to(FK5(equinox='J1975'))  # Custom frame parameters

Common Coordinate Frames

Celestial Frames

  • ICRS: International Celestial Reference System (default, most common)
  • FK5: Fifth Fundamental Catalogue (equinox J2000.0 by default)
  • FK4: Fourth Fundamental Catalogue (older, requires equinox specification)
  • GCRS: Geocentric Celestial Reference System
  • CIRS: Celestial Intermediate Reference System

Galactic Frames

  • Galactic: IAU 1958 galactic coordinates
  • Supergalactic: De Vaucouleurs supergalactic coordinates
  • Galactocentric: Galactic center-based 3D coordinates

Horizontal Frames

  • AltAz: Altitude-azimuth (observer-dependent)
  • HADec: Hour angle-declination

Ecliptic Frames

  • GeocentricMeanEcliptic: Geocentric mean ecliptic
  • BarycentricMeanEcliptic: Barycentric mean ecliptic
  • HeliocentricMeanEcliptic: Heliocentric mean ecliptic

Observer-Dependent Transformations

For altitude-azimuth coordinates, specify observation time and location:

from astropy.time import Time
from astropy.coordinates import EarthLocation, AltAz

# Define observer location
observing_location = EarthLocation(lat=40.8*u.deg, lon=-121.5*u.deg, height=1060*u.m)
# Or use named observatory
observing_location = EarthLocation.of_site('Apache Point Observatory')

# Define observation time
observing_time = Time('2023-01-15 23:00:00')

# Transform to alt-az
aa_frame = AltAz(obstime=observing_time, location=observing_location)
aa = c_icrs.transform_to(aa_frame)

print(f"Altitude: {aa.alt}")
print(f"Azimuth: {aa.az}")

Working with Distances

Add distance information for 3D coordinates:

# With distance
c = SkyCoord(ra=10*u.degree, dec=9*u.degree, distance=770*u.kpc, frame='icrs')

# Access 3D Cartesian coordinates
c.cartesian.x
c.cartesian.y
c.cartesian.z

# Distance from origin
c.distance

# 3D separation
c1 = SkyCoord(ra=10*u.degree, dec=9*u.degree, distance=10*u.pc)
c2 = SkyCoord(ra=11*u.degree, dec=10*u.degree, distance=11.5*u.pc)
sep_3d = c1.separation_3d(c2)  # 3D distance

Angular Separation

Calculate on-sky separations:

c1 = SkyCoord(ra=10*u.degree, dec=9*u.degree, frame='icrs')
c2 = SkyCoord(ra=11*u.degree, dec=10*u.degree, frame='fk5')

# Angular separation (handles frame conversion automatically)
sep = c1.separation(c2)
print(f"Separation: {sep.arcsec} arcsec")

# Position angle
pa = c1.position_angle(c2)

Catalog Matching

Match coordinates to catalog sources:

# Single target matching
catalog = SkyCoord(ra=ra_array*u.degree, dec=dec_array*u.degree)
target = SkyCoord(ra=10.5*u.degree, dec=41.2*u.degree)

# Find closest match
idx, sep2d, dist3d = target.match_to_catalog_sky(catalog)
matched_coord = catalog[idx]

# Match with maximum separation constraint
matches = target.separation(catalog) < 1*u.arcsec

Named Objects

Retrieve coordinates from online catalogs:

# Query by name (requires internet)
m31 = SkyCoord.from_name("M31")
crab = SkyCoord.from_name("Crab Nebula")
psr = SkyCoord.from_name("PSR J1012+5307")

Earth Locations

Define observer locations:

# By coordinates
location = EarthLocation(lat=40*u.deg, lon=-120*u.deg, height=1000*u.m)

# By named observatory
keck = EarthLocation.of_site('Keck Observatory')
vlt = EarthLocation.of_site('Paranal Observatory')

# By address (requires internet)
location = EarthLocation.of_address('1002 Holy Grail Court, St. Louis, MO')

# List available observatories
EarthLocation.get_site_names()

Velocity Information

Include proper motion and radial velocity:

# Proper motion
c = SkyCoord(ra=10*u.degree, dec=41*u.degree,
             pm_ra_cosdec=15*u.mas/u.yr,
             pm_dec=5*u.mas/u.yr,
             distance=150*u.pc)

# Radial velocity
c = SkyCoord(ra=10*u.degree, dec=41*u.degree,
             radial_velocity=20*u.km/u.s)

# Both
c = SkyCoord(ra=10*u.degree, dec=41*u.degree, distance=150*u.pc,
             pm_ra_cosdec=15*u.mas/u.yr, pm_dec=5*u.mas/u.yr,
             radial_velocity=20*u.km/u.s)

Representation Types

Switch between coordinate representations:

# Cartesian representation
c = SkyCoord(x=1*u.kpc, y=2*u.kpc, z=3*u.kpc,
             representation_type='cartesian', frame='icrs')

# Change representation
c.representation_type = 'cylindrical'
c.rho  # Cylindrical radius
c.phi  # Azimuthal angle
c.z    # Height

# Spherical (default for most frames)
c.representation_type = 'spherical'

Performance Tips

  1. Use arrays, not loops: Process multiple coordinates as single array
  2. Pre-compute frames: Reuse frame objects for multiple transformations
  3. Use broadcasting: Efficiently transform many positions across many times
  4. Enable interpolation: For dense time sampling, use ErfaAstromInterpolator
# Fast approach
coords = SkyCoord(ra=ra_array*u.degree, dec=dec_array*u.degree)
coords_transformed = coords.transform_to('galactic')

# Slow approach (avoid)
for ra, dec in zip(ra_array, dec_array):
    c = SkyCoord(ra=ra*u.degree, dec=dec*u.degree)
    c_transformed = c.transform_to('galactic')