Astropy: Celestial Coordinates

Documentation

For more information about the features presented below, you can read the astropy.coordinates docs.

Representing and converting coordinates

Astropy includes a framework to represent celestial coordinates and transform between them. Astropy includes common coordinate systems (ICRS, FK4, FK5, Galactic, and AltAz).

Creating coordinate objects is straightforward:

In [1]:
from astropy.coordinates import SkyCoord
from astropy import units as u
In [2]:
SkyCoord(ra=10.68458 * u.deg, dec=41.26917 * u.deg)
Out[2]:
<SkyCoord (ICRS): (ra, dec) in deg
    (10.68458, 41.26917)>
In [3]:
SkyCoord('00h42m44.3s +41d16m9s')
Out[3]:
<SkyCoord (ICRS): (ra, dec) in deg
    (10.68458333, 41.26916667)>

The individual components of a coordinate are Angle objects, and their values are accessed using special attributes:

In [4]:
c = SkyCoord('00h42m44.3s +41d16m9s')
In [5]:
c.ra
Out[5]:
$10^\circ41{}^\prime04.5{}^{\prime\prime}$
In [6]:
c.ra.hour
Out[6]:
0.7123055555555556
In [7]:
c.ra.hms
Out[7]:
hms_tuple(h=0.0, m=42.0, s=44.30000000000021)
In [8]:
c.dec
Out[8]:
$41^\circ16{}^\prime09{}^{\prime\prime}$
In [9]:
c.dec.radian
Out[9]:
0.7202828378876265

To convert to some other coordinate system, the easiest method is to use attribute-style access with short names for the built-in systems:

In [10]:
c.galactic
Out[10]:
<SkyCoord (Galactic): (l, b) in deg
    (121.17424437, -21.57288899)>

but explicit transformations via the transform_to method are also available:

In [11]:
c.transform_to('galactic')
Out[11]:
<SkyCoord (Galactic): (l, b) in deg
    (121.17424437, -21.57288899)>

The astropy.coordinates subpackage also provides a quick way to get coordinates for named objects (with an internet connection). The SkyCoord class has a method from_name(), that accepts a string and queries Sesame to retrieve coordinates for that object:

In [12]:
c_eq = SkyCoord.from_name("M16")
c_eq
Out[12]:
<SkyCoord (ICRS): (ra, dec) in deg
    (274.7, -13.8067)>

Using arrays in coordinates

Numpy arrays can be used inside coordinate objects instead of scalar floating point values (this is much more efficient that creating one coordinate object for each source). The following example demonstrates how one can combine the Table class with coordinate objects (you can download the data from here).

In [13]:
from astropy.table import Table
t = Table.read('data/2mass.tbl', format='ascii.ipac')
In [14]:
t
Out[14]:
<Table masked=True length=929>
radecclonclaterr_majerr_minerr_angdesignationj_mj_cmsigj_msigcomj_snrh_mh_cmsigh_msigcomh_snrk_mk_cmsigk_msigcomk_snrph_qualrd_flgbl_flgcc_flgndetgal_contammp_flgdistanglej_hh_kj_k
degdegarcsecarcsecdegmagmagmagmagmagmagmagmagmag
float64float64str384str416float64float64int64str512float64float64float64float64float64float64float64float64float64float64float64float64str96str96str96str96str192int64int64float64float64float64float64float64
274.429506-13.87054718h17m43.08s-13d52m13.97s0.080.084518174308-135213916.3050.1420.1436.714.0480.1070.10813.613.2570.0660.06616.5CAA2221110ss06665500975.080151256.4482.2570.7913.048
274.423821-13.8697418h17m41.72s-13d52m11.06s0.060.069018174171-135211014.8020.0580.05926.712.6350.0590.0650.111.7680.0450.04665.2AAA2221110ss66666600993.752042256.8782.1670.8673.034
274.424587-13.73962918h17m41.90s-13d44m22.66s0.080.084518174190-134422616.328------14.3450.0590.0610.413.4050.0460.04714.4UAA0220110cc00366600995.726698284.113--0.94--
274.433933-13.76950218h17m44.14s-13d46m10.21s0.080.084518174414-134610216.2810.0980.0996.814.0570.0350.03613.512.9560.0320.03321.8CAA22211100006556600942.627418278.2522.2241.1013.325
274.437013-13.88569818h17m44.88s-13d53m08.51s0.090.094518174488-135308515.171------14.4120.1520.1529.813.7420.0950.09510.6UBA6220220cc00556600964.105389252.93--0.67--
274.433996-13.75244618h17m44.16s-13d45m08.81s0.080.089018174415-134508816.54------14.5190.0830.0838.813.6040.0430.04412.0UBA0220110cc00566600953.230532281.908--0.915--
274.418138-13.7721518h17m40.35s-13d46m19.74s0.080.089018174035-134619717.98------14.610.0430.0448.113.4560.0560.05713.8UBA02201100000164500996.047248277.25--1.154--
274.433695-13.89904918h17m44.09s-13d53m56.58s0.060.069018174408-135356513.0110.0210.024139.010.9170.020.021243.810.0130.0170.019328.3AAA22211100066666600990.166399250.4662.0940.9042.998
274.425482-13.7714918h17m42.12s-13d46m17.36s0.080.0813518174211-134617316.086------13.7090.0650.06618.612.5030.0440.04533.1UAA62201200c00555500970.896919277.582--1.206--
................................................................................................
274.81801-14.00124518h19m16.32s-14d00m04.48s0.180.16118191632-140004416.240.1130.1135.615.5310.1640.1642.515.252------CDU22011000006060000809.817146149.610.709----
274.822709-14.03725418h19m17.45s-14d02m14.11s0.070.074518191745-140214115.9990.0970.0987.014.0090.0320.03310.013.0770.0350.03616.4CAA22211100006265600931.339773152.7791.990.9322.922
274.880758-13.9995618h19m31.38s-13d59m58.42s0.060.069018193138-135958414.1630.0350.03737.811.1790.020.021135.69.7650.0170.019347.1AAA22211100055666600935.512452137.7622.9841.4144.398
274.652526-14.05510618h18m36.61s-14d03m18.38s0.060.069018183660-140318315.0350.0520.05419.413.0990.040.04127.512.2540.0410.04141.7AAA222111c0056666600908.109808190.6821.9360.8452.781
274.760586-13.99992718h19m02.54s-13d59m59.74s0.080.089018190254-135959716.3290.1220.1235.514.4880.0670.0676.413.6170.0510.05211.1CCA22211100006061600724.557553163.2271.8410.8712.712
274.831132-14.02002718h19m19.47s-14d01m12.10s0.080.084518191947-140112016.203------13.2380.020.02120.412.0160.0230.02443.6UAA02201100000666600891.347132149.27--1.222--
274.972435-13.76037418h19m53.38s-13d45m37.35s0.120.111018195338-134537317.472------16.755------14.4130.0840.0844.8UUD00200100000000600964.82893379.963------
274.870009-13.81777518h19m28.80s-13d49m03.99s0.080.084518192880-134903916.933------14.5140.0640.0656.312.9570.0410.04118.4UCA02201100000266600592.99805893.69--1.557--
274.735323-13.94157518h18m56.48s-13d56m29.67s0.140.144518185647-135629616.643------14.88------14.2910.1160.1176.0UUC00200100000000400498.524438165.968------
274.866294-13.84177818h19m27.91s-13d50m30.40s0.080.084518192791-135030415.615------13.9110.0750.07510.912.7650.1340.13421.9UAE0220110cc00554500591.97725102.147--1.146--
In [15]:
c = SkyCoord(t['ra'], t['dec'])

Note that we didn't have to give the units because these are contained in the table metadata!

In [16]:
c.ra.degree[:10]
Out[16]:
array([ 274.429506,  274.423821,  274.424587,  274.433933,  274.437013,
        274.433996,  274.418138,  274.433695,  274.425482,  274.433057])

We can also pass string columns:

In [17]:
c = SkyCoord(t['clon'], t['clat'])

Converting to/from AltAz

In [18]:
import numpy as np
from astropy import units as u
from astropy.time import Time
from astropy.coordinates import SkyCoord, EarthLocation, AltAz
In [19]:
m33 = SkyCoord.from_name('M33')  
In [20]:
bear_mountain = EarthLocation(lat=41.3*u.deg, lon=-74*u.deg, height=390*u.m)
utcoffset = -4 * u.hour  # Eastern Daylight Time
time = Time('2012-7-12 23:00:00') - utcoffset
In [21]:
m33altaz = m33.transform_to(AltAz(obstime=time,location=bear_mountain))
In [22]:
m33altaz.alt
Out[22]:
$0^\circ07{}^\prime45.3475{}^{\prime\prime}$
In [23]:
m33altaz.az
Out[23]:
$47^\circ18{}^\prime29.2152{}^{\prime\prime}$

We now want to make a plot of the altitude vs time to plan observations

In [24]:
midnight = Time('2012-7-13 00:00:00') - utcoffset
delta_midnight = np.linspace(-7, 7, 100) * u.hour
In [25]:
m33altazs = m33.transform_to(AltAz(obstime=midnight+delta_midnight, location=bear_mountain))  

We can now plot the results:

In [26]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(delta_midnight, m33altazs.alt)  
plt.xlim(-2, 7)  
plt.ylim(-30, 90)  
plt.axhline(0, color='k', ls='dashed')
plt.xlabel('Hours from EDT Midnight')  
plt.ylabel('Airmass [Sec(z)]')  
plt.show()

Matching catalogs

Astropy includes functions that can help with catalog matching. Let's start from the 2MASS catalog used above and also use the WISE catalog for the same area of sky:

In [27]:
t_2mass = Table.read('data/2mass.tbl', format='ascii.ipac')['ra', 'dec', 'j_m', 'h_m', 'k_m']
t_2mass
Out[27]:
<Table masked=True length=929>
radecj_mh_mk_m
degdegmagmagmag
float64float64float64float64float64
274.429506-13.87054716.30514.04813.257
274.423821-13.8697414.80212.63511.768
274.424587-13.73962916.32814.34513.405
274.433933-13.76950216.28114.05712.956
274.437013-13.88569815.17114.41213.742
274.433996-13.75244616.5414.51913.604
274.418138-13.7721517.9814.6113.456
274.433695-13.89904913.01110.91710.013
274.425482-13.7714916.08613.70912.503
...............
274.81801-14.00124516.2415.53115.252
274.822709-14.03725415.99914.00913.077
274.880758-13.9995614.16311.1799.765
274.652526-14.05510615.03513.09912.254
274.760586-13.99992716.32914.48813.617
274.831132-14.02002716.20313.23812.016
274.972435-13.76037417.47216.75514.413
274.870009-13.81777516.93314.51412.957
274.735323-13.94157516.64314.8814.291
274.866294-13.84177815.61513.91112.765
In [28]:
t_wise = Table.read('data/wise.tbl', format='ascii.ipac')['designation', 'ra', 'dec', 'w1mpro', 'w2mpro', 'w3mpro', 'w4mpro']
t_wise
Out[28]:
<Table masked=True length=17816>
designationradecw1mprow2mprow3mprow4mpro
degdegmagmagmagmag
str608float64float64float64float64float64float64
J181752.24-141213.2274.4676959-14.203691410.00910.04710.1978.298
J181751.14-141210.7274.463119-14.202994111.0611.12910.58.215
J181751.89-141122.0274.4662354-14.189444511.59811.7289.4526.486
J181752.41-141141.8274.4684096-14.194951311.70911.9379.7597.189
J181750.20-141145.3274.4592003-14.19593348.8518.867.8446.148
J181750.22-141217.2274.4592581-14.204790611.93312.28511.6137.653
J181751.35-141147.6274.4639589-14.19656889.8159.9319.1157.549
J181756.19-141144.7274.4841457-14.195767610.33410.4589.2297.273
J181756.80-141145.0274.4866976-14.1958619.93810.00210.27.299
.....................
J181823.85-141545.4274.5994027-14.26261925.295.0854.0442.677
J181823.55-141525.8274.5981294-14.25718379.2539.1317.6354.545
J181821.52-141549.8274.5896669-14.263834911.04611.3779.0286.143
J181825.74-141529.3274.607255-14.258140911.13411.2129.6856.36
J181826.18-141546.2274.6090842-14.26283718.6928.8348.866.675
J181825.76-141609.2274.6073677-14.269241111.40111.349.266.217
J181826.07-141624.5274.6086441-14.27347398.5268.6348.7566.527
J181824.83-141619.9274.603471-14.27219817.8737.9367.5865.642
J181823.90-141609.1274.5996039-14.26921115.5755.7335.0363.429
J181829.04-141803.8274.6210114-14.301068611.53111.79310.0066.503
In [29]:
c_2mass = SkyCoord(t_2mass['ra'], t_2mass['dec'])
c_wise = SkyCoord(t_wise['ra'], t_wise['dec'])
In [30]:
idx_wise, idx_2mass, d2d, d3d = c_2mass.search_around_sky(c_wise, 5 * u.arcsec)
In [31]:
t_2mass[idx_2mass]
Out[31]:
<Table masked=True length=269>
radecj_mh_mk_m
degdegmagmagmag
float64float64float64float64float64
274.624839-14.05159716.0313.82313.145
274.6045-14.06180213.03111.23410.251
274.605645-14.06124715.09913.27912.46
274.623156-14.067615.03813.24512.551
274.797491-14.06662413.96513.01912.61
274.798888-13.88142714.39812.73811.863
274.779886-13.90199716.90413.90512.479
274.763438-13.94370117.37914.32712.757
274.755625-13.91526415.84712.60611.033
...............
274.428059-13.76948415.88514.09413.181
274.425482-13.7714916.08613.70912.503
274.426632-13.77093116.44114.74113.833
274.419872-13.76501914.54911.52910.15
274.418138-13.7721517.9814.6113.456
274.420732-13.77239916.0613.73412.622
274.421593-13.7714816.04214.36413.331
274.42386-13.86588512.18810.0319.086
274.422162-13.85978215.57413.01712.021
274.421415-13.85860216.19814.69512.924
In [32]:
t_wise[idx_wise]
Out[32]:
<Table masked=True length=269>
designationradecw1mprow2mprow3mprow4mpro
degdegmagmagmagmag
str608float64float64float64float64float64float64
J181829.96-140306.6274.6248577-14.051834712.46513.00410.1885.11
J181825.09-140342.1274.6045432-14.06171339.5299.4979.8155.506
J181825.09-140342.1274.6045432-14.06171339.5299.4979.8155.506
J181829.48-140403.8274.6228542-14.06772811.85212.42410.2866.192
J181911.20-140355.8274.7966965-14.065516210.73610.85711.1967.671
J181911.64-135256.2274.7985357-13.882278610.71110.967.9084.735
J181907.16-135406.2274.7798452-13.901729111.23512.8948.6525.447
J181903.18-135637.2274.7632695-13.943684110.77111.3275.4883.366
J181901.29-135454.8274.7554103-13.9152329.8349.7927.8854.777
.....................
J181742.82-134611.6274.4284175-13.76990412.09511.86.5184.286
J181742.14-134617.3274.4256164-13.771485111.40311.2927.0754.722
J181742.14-134617.3274.4256164-13.771485111.40311.2927.0754.722
J181740.77-134554.2274.419875-13.76505729.3769.1769.1984.708
J181740.10-134616.4274.4171127-13.771226512.44712.8329.1786.375
J181741.04-134619.8274.4210011-13.772176511.56911.6558.6066.116
J181741.04-134619.8274.4210011-13.772176511.56911.6558.6066.116
J181741.72-135157.2274.4238584-13.86589868.5198.6067.8444.485
J181741.27-135135.1274.4219657-13.859757311.33111.2929.8974.96
J181741.27-135135.1274.4219657-13.859757311.33111.2929.8974.96
In [33]:
from astropy.table import hstack
In [34]:
t_merged = hstack([t_2mass[idx_2mass], t_wise[idx_wise]])
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'int'> and <class 'int'>, choosing value=17816 [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'int'> and <class 'int'>, choosing value=17816
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='00:00:48.73022' [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='00:00:48.73022'
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='2015-05-31 09:54:35' [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='2015-05-31 09:54:35'
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='ADS/IRSA.Gator#2015/0531/095435_22394' [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='ADS/IRSA.Gator#2015/0531/095435_22394'
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='AllWISE Source Catalog (wise_allwise_p3as_psd)' [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='AllWISE Source Catalog (wise_allwise_p3as_psd)'
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='within 0.5 deg of  ra=274.70073 dec=-13.80723 Eq J2000 ' [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value='within 0.5 deg of  ra=274.70073 dec=-13.80723 Eq J2000 '
WARNING: MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value="'WHERE (no constraints)SELECT (47 column names follow in next row.)" [astropy.utils.metadata]
WARNING:astropy:MergeConflictWarning: Cannot merge meta key 'value' types <class 'str'> and <class 'str'>, choosing value="'WHERE (no constraints)SELECT (47 column names follow in next row.)"

In [35]:
plt.scatter(t_merged['k_m'] - t_merged['w4mpro'],
            t_merged['j_m'] - t_merged['k_m'])
plt.xlabel("K - W4")
plt.ylabel("J - K")
Out[35]:
<matplotlib.text.Text at 0x10daef080>

Practical Exercises

Level 1

Find the coordinates of the Crab Nebula in ICRS coordinates, and convert them to Galactic Coordinates.

Level 2

Starting from this table in VO table format (this is the ROSAT all-sky catalog), read in the sources, use the RA and Dec columns to instantiate a coordinate object, then convert to Galactic coordinates. Make a plot of latitude versus longitude.

Level 3

Once you have done Level 2, make an Aitoff projection map of the sources in Galactic coordinates. Then, try and match the ROSAT catalog with other catalogs that you have access to.