Coordinates and units¶
This is the second in a series of notebooks related to astronomy data.
As a running example, we are replicating parts of the analysis in a recent paper, “Off the beaten path: Gaia reveals GD-1 stars outside of the main stream” by Adrian M. Price-Whelan and Ana Bonaca.
In the first notebook, we wrote ADQL queries and used them to select and download data from the Gaia server.
In this notebook, we’ll pick up where we left off and write a query to select stars from the region of the sky where we expect GD-1 to be.
Outline¶
We’ll start with an example that does a “cone search”; that is, it selects stars that appear in a circular region of the sky.
Then, to select stars in the vicinity of GD-1, we’ll:
Use
Quantityobjects to represent measurements with units.Use the
Galalibrary to convert coordinates from one frame to another.Use the ADQL keywords
POLYGON,CONTAINS, andPOINTto select stars that fall within a polygonal region.Submit a query and download the results.
Store the results in a FITS file.
After completing this lesson, you should be able to
Use Python string formatting to compose more complex ADQL queries.
Work with coordinates and other quantities that have units.
Download the results of a query and store them in a file.
Selecting a region¶
One of the most common ways to restrict a query is to select stars in a particular region of the sky.
For example, here’s a query from the Gaia archive documentation that selects “all the objects … in a circular region centered at (266.41683, -29.00781) with a search radius of 5 arcmin (0.08333 deg).”
query = """
SELECT
TOP 10 source_id
FROM gaiadr2.gaia_source
WHERE 1=CONTAINS(
POINT(ra, dec),
CIRCLE(266.41683, -29.00781, 0.08333333))
"""
This query uses three keywords that are specific to ADQL (not SQL):
POINT: a location in ICRS coordinates, specified in degrees of right ascension and declination.CIRCLE: a circle where the first two values are the coordinates of the center and the third is the radius in degrees.CONTAINS: a function that returns1if aPOINTis contained in a shape and0otherwise.
Here is the documentation of CONTAINS.
A query like this is called a cone search because it selects stars in a cone.
Here’s how we run it.
from astroquery.gaia import Gaia
job = Gaia.launch_job(query)
result = job.get_results()
result
Created TAP+ (v1.2.1) - Connection:
Host: gea.esac.esa.int
Use HTTPS: True
Port: 443
SSL Port: 443
Created TAP+ (v1.2.1) - Connection:
Host: geadata.esac.esa.int
Use HTTPS: True
Port: 443
SSL Port: 443
| source_id |
|---|
| int64 |
| 4057468321929794432 |
| 4057468287575835392 |
| 4057482027171038976 |
| 4057470349160630656 |
| 4057470039924301696 |
| 4057469868125641984 |
| 4057468351995073024 |
| 4057469661959554560 |
| 4057470520960672640 |
| 4057470555320409600 |
Exercise¶
When you are debugging queries like this, you can use TOP to limit the size of the results, but then you still don’t know how big the results will be.
An alternative is to use COUNT, which asks for the number of rows that would be selected, but it does not return them.
In the previous query, replace TOP 10 source_id with COUNT(source_id) and run the query again. How many stars has Gaia identified in the cone we searched?
# Solution
query = """
SELECT
COUNT(source_id)
FROM gaiadr2.gaia_source
WHERE 1=CONTAINS(
POINT(ra, dec),
CIRCLE(266.41683, -29.00781, 0.08333333))
"""
Getting GD-1 Data¶
From the Price-Whelan and Bonaca paper, we will try to reproduce Figure 1, which includes this representation of stars likely to belong to GD-1:
Along the axis of right ascension (\(\phi_1\)) the figure extends from -100 to 20 degrees.
Along the axis of declination (\(\phi_2\)) the figure extends from about -8 to 4 degrees.
Ideally, we would select all stars from this rectangle, but there are more than 10 million of them, so
That would be difficult to work with,
As anonymous users, we are limited to 3 million rows in a single query, and
While we are developing and testing code, it will be faster to work with a smaller dataset.
So we’ll start by selecting stars in a smaller rectangle, from -55 to -45 degrees right ascension and -8 to 4 degrees of declination.
But first we let’s see how to represent quantities with units like degrees.
Working with coordinates¶
Coordinates are physical quantities, which means that they have two parts, a value and a unit.
For example, the coordinate \(30^{\circ}\) has value 30 and its units are degrees.
Until recently, most scientific computation was done with values only; units were left out of the program altogether, often with disastrous results.
Astropy provides tools for including units explicitly in computations, which makes it possible to detect errors before they cause disasters.
To use Astropy units, we import them like this:
import astropy.units as u
u
<module 'astropy.units' from '/home/downey/anaconda3/envs/AstronomicalData/lib/python3.8/site-packages/astropy/units/__init__.py'>
u is an object that contains most common units and all SI units.
You can use dir to list them, but you should also read the documentation.
dir(u)
['A',
'AA',
'AB',
'ABflux',
'ABmag',
'AU',
'Angstrom',
'B',
'Ba',
'Barye',
'Bi',
'Biot',
'Bol',
'Bq',
'C',
'Celsius',
'Ci',
'CompositeUnit',
'D',
'Da',
'Dalton',
'Debye',
'Decibel',
'DecibelUnit',
'Dex',
'DexUnit',
'EA',
'EAU',
'EB',
'EBa',
'EC',
'ED',
'EF',
'EG',
'EGal',
'EH',
'EHz',
'EJ',
'EJy',
'EK',
'EL',
'EN',
'EOhm',
'EP',
'EPa',
'ER',
'ERy',
'ES',
'ESt',
'ET',
'EV',
'EW',
'EWb',
'Ea',
'Eadu',
'Earcmin',
'Earcsec',
'Eau',
'Eb',
'Ebarn',
'Ebeam',
'Ebin',
'Ebit',
'Ebyte',
'Ecd',
'Echan',
'Ecount',
'Ect',
'Ed',
'Edeg',
'Edyn',
'EeV',
'Eerg',
'Eg',
'Eh',
'EiB',
'Eib',
'Eibit',
'Eibyte',
'Ek',
'El',
'Elm',
'Elx',
'Elyr',
'Em',
'Emag',
'Emin',
'Emol',
'Eohm',
'Epc',
'Eph',
'Ephoton',
'Epix',
'Epixel',
'Erad',
'Es',
'Esr',
'Eu',
'Evox',
'Evoxel',
'Eyr',
'F',
'Farad',
'Fr',
'Franklin',
'FunctionQuantity',
'FunctionUnitBase',
'G',
'GA',
'GAU',
'GB',
'GBa',
'GC',
'GD',
'GF',
'GG',
'GGal',
'GH',
'GHz',
'GJ',
'GJy',
'GK',
'GL',
'GN',
'GOhm',
'GP',
'GPa',
'GR',
'GRy',
'GS',
'GSt',
'GT',
'GV',
'GW',
'GWb',
'Ga',
'Gadu',
'Gal',
'Garcmin',
'Garcsec',
'Gau',
'Gauss',
'Gb',
'Gbarn',
'Gbeam',
'Gbin',
'Gbit',
'Gbyte',
'Gcd',
'Gchan',
'Gcount',
'Gct',
'Gd',
'Gdeg',
'Gdyn',
'GeV',
'Gerg',
'Gg',
'Gh',
'GiB',
'Gib',
'Gibit',
'Gibyte',
'Gk',
'Gl',
'Glm',
'Glx',
'Glyr',
'Gm',
'Gmag',
'Gmin',
'Gmol',
'Gohm',
'Gpc',
'Gph',
'Gphoton',
'Gpix',
'Gpixel',
'Grad',
'Gs',
'Gsr',
'Gu',
'Gvox',
'Gvoxel',
'Gyr',
'H',
'Henry',
'Hertz',
'Hz',
'IrreducibleUnit',
'J',
'Jansky',
'Joule',
'Jy',
'K',
'Kayser',
'Kelvin',
'KiB',
'Kib',
'Kibit',
'Kibyte',
'L',
'L_bol',
'L_sun',
'LogQuantity',
'LogUnit',
'Lsun',
'MA',
'MAU',
'MB',
'MBa',
'MC',
'MD',
'MF',
'MG',
'MGal',
'MH',
'MHz',
'MJ',
'MJy',
'MK',
'ML',
'MN',
'MOhm',
'MP',
'MPa',
'MR',
'MRy',
'MS',
'MSt',
'MT',
'MV',
'MW',
'MWb',
'M_bol',
'M_e',
'M_earth',
'M_jup',
'M_jupiter',
'M_p',
'M_sun',
'Ma',
'Madu',
'MagUnit',
'Magnitude',
'Marcmin',
'Marcsec',
'Mau',
'Mb',
'Mbarn',
'Mbeam',
'Mbin',
'Mbit',
'Mbyte',
'Mcd',
'Mchan',
'Mcount',
'Mct',
'Md',
'Mdeg',
'Mdyn',
'MeV',
'Mearth',
'Merg',
'Mg',
'Mh',
'MiB',
'Mib',
'Mibit',
'Mibyte',
'Mjup',
'Mjupiter',
'Mk',
'Ml',
'Mlm',
'Mlx',
'Mlyr',
'Mm',
'Mmag',
'Mmin',
'Mmol',
'Mohm',
'Mpc',
'Mph',
'Mphoton',
'Mpix',
'Mpixel',
'Mrad',
'Ms',
'Msr',
'Msun',
'Mu',
'Mvox',
'Mvoxel',
'Myr',
'N',
'NamedUnit',
'Newton',
'Ohm',
'P',
'PA',
'PAU',
'PB',
'PBa',
'PC',
'PD',
'PF',
'PG',
'PGal',
'PH',
'PHz',
'PJ',
'PJy',
'PK',
'PL',
'PN',
'POhm',
'PP',
'PPa',
'PR',
'PRy',
'PS',
'PSt',
'PT',
'PV',
'PW',
'PWb',
'Pa',
'Padu',
'Parcmin',
'Parcsec',
'Pascal',
'Pau',
'Pb',
'Pbarn',
'Pbeam',
'Pbin',
'Pbit',
'Pbyte',
'Pcd',
'Pchan',
'Pcount',
'Pct',
'Pd',
'Pdeg',
'Pdyn',
'PeV',
'Perg',
'Pg',
'Ph',
'PiB',
'Pib',
'Pibit',
'Pibyte',
'Pk',
'Pl',
'Plm',
'Plx',
'Plyr',
'Pm',
'Pmag',
'Pmin',
'Pmol',
'Pohm',
'Ppc',
'Pph',
'Pphoton',
'Ppix',
'Ppixel',
'Prad',
'PrefixUnit',
'Ps',
'Psr',
'Pu',
'Pvox',
'Pvoxel',
'Pyr',
'Quantity',
'QuantityInfo',
'QuantityInfoBase',
'R',
'R_earth',
'R_jup',
'R_jupiter',
'R_sun',
'Rayleigh',
'Rearth',
'Rjup',
'Rjupiter',
'Rsun',
'Ry',
'S',
'ST',
'STflux',
'STmag',
'Siemens',
'SpecificTypeQuantity',
'St',
'Sun',
'T',
'TA',
'TAU',
'TB',
'TBa',
'TC',
'TD',
'TF',
'TG',
'TGal',
'TH',
'THz',
'TJ',
'TJy',
'TK',
'TL',
'TN',
'TOhm',
'TP',
'TPa',
'TR',
'TRy',
'TS',
'TSt',
'TT',
'TV',
'TW',
'TWb',
'Ta',
'Tadu',
'Tarcmin',
'Tarcsec',
'Tau',
'Tb',
'Tbarn',
'Tbeam',
'Tbin',
'Tbit',
'Tbyte',
'Tcd',
'Tchan',
'Tcount',
'Tct',
'Td',
'Tdeg',
'Tdyn',
'TeV',
'Terg',
'Tesla',
'Tg',
'Th',
'TiB',
'Tib',
'Tibit',
'Tibyte',
'Tk',
'Tl',
'Tlm',
'Tlx',
'Tlyr',
'Tm',
'Tmag',
'Tmin',
'Tmol',
'Tohm',
'Tpc',
'Tph',
'Tphoton',
'Tpix',
'Tpixel',
'Trad',
'Ts',
'Tsr',
'Tu',
'Tvox',
'Tvoxel',
'Tyr',
'Unit',
'UnitBase',
'UnitConversionError',
'UnitTypeError',
'UnitsError',
'UnitsWarning',
'UnrecognizedUnit',
'V',
'Volt',
'W',
'Watt',
'Wb',
'Weber',
'YA',
'YAU',
'YB',
'YBa',
'YC',
'YD',
'YF',
'YG',
'YGal',
'YH',
'YHz',
'YJ',
'YJy',
'YK',
'YL',
'YN',
'YOhm',
'YP',
'YPa',
'YR',
'YRy',
'YS',
'YSt',
'YT',
'YV',
'YW',
'YWb',
'Ya',
'Yadu',
'Yarcmin',
'Yarcsec',
'Yau',
'Yb',
'Ybarn',
'Ybeam',
'Ybin',
'Ybit',
'Ybyte',
'Ycd',
'Ychan',
'Ycount',
'Yct',
'Yd',
'Ydeg',
'Ydyn',
'YeV',
'Yerg',
'Yg',
'Yh',
'Yk',
'Yl',
'Ylm',
'Ylx',
'Ylyr',
'Ym',
'Ymag',
'Ymin',
'Ymol',
'Yohm',
'Ypc',
'Yph',
'Yphoton',
'Ypix',
'Ypixel',
'Yrad',
'Ys',
'Ysr',
'Yu',
'Yvox',
'Yvoxel',
'Yyr',
'ZA',
'ZAU',
'ZB',
'ZBa',
'ZC',
'ZD',
'ZF',
'ZG',
'ZGal',
'ZH',
'ZHz',
'ZJ',
'ZJy',
'ZK',
'ZL',
'ZN',
'ZOhm',
'ZP',
'ZPa',
'ZR',
'ZRy',
'ZS',
'ZSt',
'ZT',
'ZV',
'ZW',
'ZWb',
'Za',
'Zadu',
'Zarcmin',
'Zarcsec',
'Zau',
'Zb',
'Zbarn',
'Zbeam',
'Zbin',
'Zbit',
'Zbyte',
'Zcd',
'Zchan',
'Zcount',
'Zct',
'Zd',
'Zdeg',
'Zdyn',
'ZeV',
'Zerg',
'Zg',
'Zh',
'Zk',
'Zl',
'Zlm',
'Zlx',
'Zlyr',
'Zm',
'Zmag',
'Zmin',
'Zmol',
'Zohm',
'Zpc',
'Zph',
'Zphoton',
'Zpix',
'Zpixel',
'Zrad',
'Zs',
'Zsr',
'Zu',
'Zvox',
'Zvoxel',
'Zyr',
'__builtins__',
'__cached__',
'__doc__',
'__file__',
'__loader__',
'__name__',
'__package__',
'__path__',
'__spec__',
'a',
'aA',
'aAU',
'aB',
'aBa',
'aC',
'aD',
'aF',
'aG',
'aGal',
'aH',
'aHz',
'aJ',
'aJy',
'aK',
'aL',
'aN',
'aOhm',
'aP',
'aPa',
'aR',
'aRy',
'aS',
'aSt',
'aT',
'aV',
'aW',
'aWb',
'aa',
'aadu',
'aarcmin',
'aarcsec',
'aau',
'ab',
'abA',
'abC',
'abampere',
'abarn',
'abcoulomb',
'abeam',
'abin',
'abit',
'abyte',
'acd',
'achan',
'acount',
'act',
'ad',
'add_enabled_equivalencies',
'add_enabled_units',
'adeg',
'adu',
'adyn',
'aeV',
'aerg',
'ag',
'ah',
'ak',
'al',
'allclose',
'alm',
'alx',
'alyr',
'am',
'amag',
'amin',
'amol',
'amp',
'ampere',
'angstrom',
'annum',
'aohm',
'apc',
'aph',
'aphoton',
'apix',
'apixel',
'arad',
'arcmin',
'arcminute',
'arcsec',
'arcsecond',
'asr',
'astronomical_unit',
'astrophys',
'attoBarye',
'attoDa',
'attoDalton',
'attoDebye',
'attoFarad',
'attoGauss',
'attoHenry',
'attoHertz',
'attoJansky',
'attoJoule',
'attoKayser',
'attoKelvin',
'attoNewton',
'attoOhm',
'attoPascal',
'attoRayleigh',
'attoSiemens',
'attoTesla',
'attoVolt',
'attoWatt',
'attoWeber',
'attoamp',
'attoampere',
'attoannum',
'attoarcminute',
'attoarcsecond',
'attoastronomical_unit',
'attobarn',
'attobarye',
'attobit',
'attobyte',
'attocandela',
'attocoulomb',
'attocount',
'attoday',
'attodebye',
'attodegree',
'attodyne',
'attoelectronvolt',
'attofarad',
'attogal',
'attogauss',
'attogram',
'attohenry',
'attohertz',
'attohour',
'attohr',
'attojansky',
'attojoule',
'attokayser',
'attolightyear',
'attoliter',
'attolumen',
'attolux',
'attometer',
'attominute',
'attomole',
'attonewton',
'attoparsec',
'attopascal',
'attophoton',
'attopixel',
'attopoise',
'attoradian',
'attorayleigh',
'attorydberg',
'attosecond',
'attosiemens',
'attosteradian',
'attostokes',
'attotesla',
'attovolt',
'attovoxel',
'attowatt',
'attoweber',
'attoyear',
'au',
'avox',
'avoxel',
'ayr',
'b',
'bar',
'barn',
'barye',
'beam',
'beam_angular_area',
'becquerel',
'bin',
'binary_prefixes',
'bit',
'bol',
'brightness_temperature',
'byte',
'cA',
'cAU',
'cB',
'cBa',
'cC',
'cD',
'cF',
'cG',
'cGal',
'cH',
'cHz',
'cJ',
'cJy',
'cK',
'cL',
'cN',
'cOhm',
'cP',
'cPa',
'cR',
'cRy',
'cS',
'cSt',
'cT',
'cV',
'cW',
'cWb',
'ca',
'cadu',
'candela',
'carcmin',
'carcsec',
'cau',
'cb',
'cbarn',
'cbeam',
'cbin',
'cbit',
'cbyte',
'ccd',
'cchan',
'ccount',
'cct',
'cd',
'cdeg',
'cdyn',
'ceV',
'centiBarye',
'centiDa',
'centiDalton',
'centiDebye',
'centiFarad',
'centiGauss',
'centiHenry',
'centiHertz',
'centiJansky',
'centiJoule',
'centiKayser',
'centiKelvin',
'centiNewton',
'centiOhm',
'centiPascal',
'centiRayleigh',
'centiSiemens',
'centiTesla',
'centiVolt',
'centiWatt',
'centiWeber',
'centiamp',
'centiampere',
'centiannum',
'centiarcminute',
'centiarcsecond',
'centiastronomical_unit',
'centibarn',
'centibarye',
'centibit',
'centibyte',
'centicandela',
'centicoulomb',
'centicount',
'centiday',
'centidebye',
'centidegree',
'centidyne',
'centielectronvolt',
'centifarad',
'centigal',
'centigauss',
'centigram',
'centihenry',
'centihertz',
'centihour',
'centihr',
'centijansky',
'centijoule',
'centikayser',
'centilightyear',
'centiliter',
'centilumen',
'centilux',
'centimeter',
'centiminute',
'centimole',
'centinewton',
'centiparsec',
'centipascal',
'centiphoton',
'centipixel',
'centipoise',
'centiradian',
'centirayleigh',
'centirydberg',
'centisecond',
'centisiemens',
'centisteradian',
'centistokes',
'centitesla',
'centivolt',
'centivoxel',
'centiwatt',
'centiweber',
'centiyear',
'cerg',
'cg',
'cgs',
'ch',
'chan',
'ck',
'cl',
'clm',
'clx',
'clyr',
'cm',
'cmag',
'cmin',
'cmol',
'cohm',
'core',
'coulomb',
'count',
'cpc',
'cph',
'cphoton',
'cpix',
'cpixel',
'crad',
'cs',
'csr',
'ct',
'cu',
'curie',
'cvox',
'cvoxel',
'cy',
'cycle',
'cyr',
'd',
'dA',
'dAU',
'dB',
'dBa',
'dC',
'dD',
'dF',
'dG',
'dGal',
'dH',
'dHz',
'dJ',
'dJy',
'dK',
'dL',
'dN',
'dOhm',
'dP',
'dPa',
'dR',
'dRy',
'dS',
'dSt',
'dT',
...]
To create a quantity, we multiply a value by a unit.
coordinate = 30 * u.deg
type(coordinate)
astropy.units.quantity.Quantity
The result is a Quantity object.
Jupyter knows how to display Quantities like this:
coordinate
Selecting a rectangle¶
Now we’ll select a rectangle from -55 to -45 degrees right ascension and -8 to 4 degrees of declination.
We’ll define variables to contain these limits.
phi1_min = -55
phi1_max = -45
phi2_min = -8
phi2_max = 4
To represent a rectangle, we’ll use two lists of coordinates and multiply by their units.
phi1_rect = [phi1_min, phi1_min, phi1_max, phi1_max] * u.deg
phi2_rect = [phi2_min, phi2_max, phi2_max, phi2_min] * u.deg
phi1_rect and phi2_rect represent the coordinates of the corners of a rectangle.
But they are in “a Heliocentric spherical coordinate system defined by the orbit of the GD1 stream”
In order to use them in a Gaia query, we have to convert them to International Celestial Reference System (ICRS) coordinates. We can do that by storing the coordinates in a GD1Koposov10 object provided by Gala.
import gala.coordinates as gc
corners = gc.GD1Koposov10(phi1=phi1_rect, phi2=phi2_rect)
type(corners)
gala.coordinates.gd1.GD1Koposov10
We can display the result like this:
corners
<GD1Koposov10 Coordinate: (phi1, phi2) in deg
[(-55., -8.), (-55., 4.), (-45., 4.), (-45., -8.)]>
Now we can use transform_to to convert to ICRS coordinates.
import astropy.coordinates as coord
corners_icrs = corners.transform_to(coord.ICRS)
type(corners_icrs)
astropy.coordinates.builtin_frames.icrs.ICRS
The result is an ICRS object.
corners_icrs
<ICRS Coordinate: (ra, dec) in deg
[(146.27533314, 19.26190982), (135.42163944, 25.87738723),
(141.60264825, 34.3048303 ), (152.81671045, 27.13611254)]>
Notice that a rectangle in one coordinate system is not necessarily a rectangle in another. In this example, the result is a polygon.
Selecting a polygon¶
In order to use this polygon as part of an ADQL query, we have to convert it to a string with a comma-separated list of coordinates, as in this example:
"""
POLYGON(143.65, 20.98,
134.46, 26.39,
140.58, 34.85,
150.16, 29.01)
"""
corners_icrs behaves like a list, so we can use a for loop to iterate through the points.
for point in corners_icrs:
print(point)
<ICRS Coordinate: (ra, dec) in deg
(146.27533314, 19.26190982)>
<ICRS Coordinate: (ra, dec) in deg
(135.42163944, 25.87738723)>
<ICRS Coordinate: (ra, dec) in deg
(141.60264825, 34.3048303)>
<ICRS Coordinate: (ra, dec) in deg
(152.81671045, 27.13611254)>
From that, we can select the coordinates ra and dec:
for point in corners_icrs:
print(point.ra, point.dec)
146d16m31.1993s 19d15m42.8754s
135d25m17.902s 25d52m38.594s
141d36m09.5337s 34d18m17.3891s
152d49m00.1576s 27d08m10.0051s
The results are quantities with units, but if we select the value part, we get a dimensionless floating-point number.
for point in corners_icrs:
print(point.ra.value, point.dec.value)
146.27533313607782 19.261909820533692
135.42163944306296 25.87738722767213
141.60264825107333 34.304830296257144
152.81671044675923 27.136112541397996
We can use string format to convert these numbers to strings.
point_base = "{point.ra.value}, {point.dec.value}"
t = [point_base.format(point=point)
for point in corners_icrs]
t
['146.27533313607782, 19.261909820533692',
'135.42163944306296, 25.87738722767213',
'141.60264825107333, 34.304830296257144',
'152.81671044675923, 27.136112541397996']
The result is a list of strings, which we can join into a single string using join.
point_list = ', '.join(t)
point_list
'146.27533313607782, 19.261909820533692, 135.42163944306296, 25.87738722767213, 141.60264825107333, 34.304830296257144, 152.81671044675923, 27.136112541397996'
Notice that we invoke join on a string and pass the list as an argument.
Before we can assemble the query, we need columns again (as we saw in the previous notebook).
columns = 'source_id, ra, dec, pmra, pmdec, parallax, parallax_error, radial_velocity'
Here’s the base for the query, with format specifiers for columns and point_list.
query_base = """SELECT {columns}
FROM gaiadr2.gaia_source
WHERE parallax < 1
AND bp_rp BETWEEN -0.75 AND 2
AND 1 = CONTAINS(POINT(ra, dec),
POLYGON({point_list}))
"""
And here’s the result:
query = query_base.format(columns=columns,
point_list=point_list)
print(query)
SELECT source_id, ra, dec, pmra, pmdec, parallax, parallax_error, radial_velocity
FROM gaiadr2.gaia_source
WHERE parallax < 1
AND bp_rp BETWEEN -0.75 AND 2
AND 1 = CONTAINS(POINT(ra, dec),
POLYGON(146.27533313607782, 19.261909820533692, 135.42163944306296, 25.87738722767213, 141.60264825107333, 34.304830296257144, 152.81671044675923, 27.136112541397996))
As always, we should take a minute to proof-read the query before we launch it.
The result will be bigger than our previous queries, so it will take a little longer.
job = Gaia.launch_job_async(query)
print(job)
INFO: Query finished. [astroquery.utils.tap.core]
<Table length=140340>
name dtype unit description n_bad
--------------- ------- -------- ------------------------------------------------------------------ ------
source_id int64 Unique source identifier (unique within a particular Data Release) 0
ra float64 deg Right ascension 0
dec float64 deg Declination 0
pmra float64 mas / yr Proper motion in right ascension direction 0
pmdec float64 mas / yr Proper motion in declination direction 0
parallax float64 mas Parallax 0
parallax_error float64 mas Standard error of parallax 0
radial_velocity float64 km / s Radial velocity 139374
Jobid: 1605624329053O
Phase: COMPLETED
Owner: None
Output file: async_20201117094529.vot
Results: None
Here are the results.
results = job.get_results()
len(results)
140340
There are more than 100,000 stars in this polygon, but that’s a manageable size to work with.
Saving results¶
This is the set of stars we’ll work with in the next step. But since we have a substantial dataset now, this is a good time to save it.
Storing the data in a file means we can shut down this notebook and pick up where we left off without running the previous query again.
Astropy Table objects provide write, which writes the table to disk.
filename = 'gd1_results.fits'
results.write(filename, overwrite=True)
Because the filename ends with fits, the table is written in the FITS format, which preserves the metadata associated with the table.
If the file already exists, the overwrite argument causes it to be overwritten.
To see how big the file is, we can use ls with the -lh option, which prints information about the file including its size in human-readable form.
!ls -lh gd1_results.fits
-rw-rw-r-- 1 downey downey 8.6M Nov 17 09:45 gd1_results.fits
The file is about 8.6 MB. If you are using Windows, ls might not work; in that case, try:
!dir gd1_results.fits
Summary¶
In this notebook, we composed more complex queries to select stars within a polygonal region of the sky. Then we downloaded the results and saved them in a FITS file.
In the next notebook, we’ll reload the data from this file and replicate the next step in the analysis, using proper motion to identify stars likely to be in GD-1.
Best practices¶
For measurements with units, use
Quantityobjects that represent units explicitly and check for errors.Use the
formatfunction to compose queries; it is often faster and less error-prone.Develop queries incrementally: start with something simple, test it, and add a little bit at a time.
Once you have a query working, save the data in a local file. If you shut down the notebook and come back to it later, you can reload the file; you don’t have to run the query again.