A new MAST interface supports queries to the current and previous versions of the Hubble Source Catalog. It allows searches of the summary table (with multi-filter mean photometry) and the detailed table (with all the multi-epoch measurements). It also has an associated API, which is used in this notebook.
This is based on HSC Use Case #3.
The whole process takes only 30 seconds to complete.
This notebook is available for download. Another simple notebook generates a color-magnitude diagram for the Small Magellanic Cloud in only a couple of minutes. A more complex notebook that shows how to access the proper motion tables using the HSC API is also available.
Running the notebook from top to bottom takes about 30 seconds.
This notebook requires the use of Python 3.
This needs the requests
and pillow
modules in addition to the common requirements of astropy
, numpy
and scipy
. For anaconda versions of Python the installation commands are:
conda install requests conda install pillow
%matplotlib inline
import astropy, pylab, time, sys, os, requests, json
import numpy as np
from pprint import pprint
from astropy.table import Table
import pandas as pd
from PIL import Image
from io import BytesIO, StringIO
# Set page width to fill browser for longer output lines
from IPython.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))
# set width for pprint
astropy.conf.max_width = 150
Execute HSC searches and resolve names using MAST query.
hscapiurl = "https://catalogs.mast.stsci.edu/api/v0.1/hsc"
def hsccone(ra,dec,radius,table="summary",release="v3",format="csv",magtype="magaper2",
columns=None, baseurl=hscapiurl, verbose=False,
**kw):
"""Do a cone search of the HSC catalog
Parameters
----------
ra (float): (degrees) J2000 Right Ascension
dec (float): (degrees) J2000 Declination
radius (float): (degrees) Search radius (<= 0.5 degrees)
table (string): summary, detailed, propermotions, or sourcepositions
release (string): v3 or v2
magtype (string): magaper2 or magauto (only applies to summary table)
format: csv, votable, json, table
columns: list of column names to include (None means use defaults)
baseurl: base URL for the request
verbose: print info about request
**kw: other parameters (e.g., 'numimages.gte':2)
"""
data = kw.copy()
data['ra'] = ra
data['dec'] = dec
data['radius'] = radius
return hscsearch(table=table,release=release,format=format,magtype=magtype,
columns=columns,baseurl=baseurl,verbose=verbose,**data)
def hscsearch(table="summary",release="v3",magtype="magaper2",format="csv",
columns=None, baseurl=hscapiurl, verbose=False,
**kw):
"""Do a general search of the HSC catalog (possibly without ra/dec/radius)
Parameters
----------
table (string): summary, detailed, propermotions, or sourcepositions
release (string): v3 or v2
magtype (string): magaper2 or magauto (only applies to summary table)
format: csv, votable, json, table
columns: list of column names to include (None means use defaults)
baseurl: base URL for the request
verbose: print info about request
**kw: other parameters (e.g., 'numimages.gte':2). Note this is required!
"""
data = kw.copy()
if not data:
raise ValueError("You must specify some parameters for search")
if format not in ("csv","votable","json","table"):
raise ValueError("Bad value for format")
if format == "table":
rformat = "csv"
else:
rformat = format
url = "{}.{}".format(cat2url(table,release,magtype,baseurl=baseurl),rformat)
if columns:
# check that column values are legal
# create a dictionary to speed this up
dcols = {}
for col in hscmetadata(table,release,magtype)['name']:
dcols[col.lower()] = 1
badcols = []
for col in columns:
if col.lower().strip() not in dcols:
badcols.append(col)
if badcols:
raise ValueError('Some columns not found in table: {}'.format(', '.join(badcols)))
# two different ways to specify a list of column values in the API
# data['columns'] = columns
data['columns'] = '[{}]'.format(','.join(columns))
# either get or post works
# r = requests.post(url, data=data)
r = requests.get(url, params=data)
if verbose:
print(r.url)
r.raise_for_status()
if format == "json":
return r.json()
elif format == "table":
# use pandas to work around bug in Windows for ascii.read
return Table.from_pandas(pd.read_csv(StringIO(r.text)))
else:
return r.text
def hscmetadata(table="summary",release="v3",magtype="magaper2",baseurl=hscapiurl):
"""Return metadata for the specified catalog and table
Parameters
----------
table (string): summary, detailed, propermotions, or sourcepositions
release (string): v3 or v2
magtype (string): magaper2 or magauto (only applies to summary table)
baseurl: base URL for the request
Returns an astropy table with columns name, type, description
"""
url = "{}/metadata".format(cat2url(table,release,magtype,baseurl=baseurl))
r = requests.get(url)
r.raise_for_status()
v = r.json()
# convert to astropy table
tab = Table(rows=[(x['name'],x['type'],x['description']) for x in v],
names=('name','type','description'))
return tab
def cat2url(table="summary",release="v3",magtype="magaper2",baseurl=hscapiurl):
"""Return URL for the specified catalog and table
Parameters
----------
table (string): summary, detailed, propermotions, or sourcepositions
release (string): v3 or v2
magtype (string): magaper2 or magauto (only applies to summary table)
baseurl: base URL for the request
Returns a string with the base URL for this request
"""
checklegal(table,release,magtype)
if table == "summary":
url = "{baseurl}/{release}/{table}/{magtype}".format(**locals())
else:
url = "{baseurl}/{release}/{table}".format(**locals())
return url
def checklegal(table,release,magtype):
"""Checks if this combination of table, release and magtype is acceptable
Raises a ValueError exception if there is problem
"""
releaselist = ("v2", "v3")
if release not in releaselist:
raise ValueError("Bad value for release (must be one of {})".format(
', '.join(releaselist)))
if release=="v2":
tablelist = ("summary", "detailed")
else:
tablelist = ("summary", "detailed", "propermotions", "sourcepositions")
if table not in tablelist:
raise ValueError("Bad value for table (for {} must be one of {})".format(
release, ", ".join(tablelist)))
if table == "summary":
magtypelist = ("magaper2", "magauto")
if magtype not in magtypelist:
raise ValueError("Bad value for magtype (must be one of {})".format(
", ".join(magtypelist)))
def mastQuery(request, url='https://mast.stsci.edu/api/v0/invoke'):
"""Perform a MAST query.
Parameters
----------
request (dictionary): The MAST request json object
url (string): The service URL
Returns the returned data content
"""
# Encoding the request as a json string
requestString = json.dumps(request)
r = requests.post(url, data={'request': requestString})
r.raise_for_status()
return r.text
def resolve(name):
"""Get the RA and Dec for an object using the MAST name resolver
Parameters
----------
name (str): Name of object
Returns RA, Dec tuple with position
"""
resolverRequest = {'service':'Mast.Name.Lookup',
'params':{'input':name,
'format':'json'
},
}
resolvedObjectString = mastQuery(resolverRequest)
resolvedObject = json.loads(resolvedObjectString)
# The resolver returns a variety of information about the resolved object,
# however for our purposes all we need are the RA and Dec
try:
objRa = resolvedObject['resolvedCoordinate'][0]['ra']
objDec = resolvedObject['resolvedCoordinate'][0]['decl']
except IndexError as e:
raise ValueError("Unknown object '{}'".format(name))
return (objRa, objDec)
The metadata
query returns information on the columns in the table. It works for any of the tables in the API (summary
, detailed
, propermotions
, sourcepositions
).
Note that the summary table has a huge number of columns! Each of the 133 filter/detector combinations has 3 columns with the magnitude, median absolute deviation (MAD, a robust measure of the scatter among the measurements), and the number of independent measurements in the filter. The filter name includes a prefix for the detector (A
=ACS/WFC, W3
=WFC3/UVIS or WFC3/IR, W2
=WFPC2) followed by the standard name of the filter. So for instance all three instruments have an F814W filter, so there are columns for A_F814W
, W3_F814W
, and W2_F814W
.
meta = hscmetadata("summary")
print(len(meta),"columns in summary")
filterlist = meta['name'][19::3].tolist()
print(len(filterlist),"filters")
pprint(filterlist, compact=True)
meta[:19]
418 columns in summary 133 filters ['W3_BLANK', 'W2_F122M', 'W2_F160BN15', 'W2_F160BW', 'W2_F170W', 'W2_F185W', 'W3_F200LP', 'W3_F218W', 'W2_F218W', 'W3_F225W', 'W3_FQ232N', 'W3_FQ243N', 'W2_F255W', 'W3_F275W', 'W3_F280N', 'W3_G280', 'W2_F300W', 'W3_F300X', 'W3_F336W', 'W2_F336W', 'W3_F343N', 'W2_F343N', 'W3_F350LP', 'W3_F373N', 'W2_F375N', 'W3_FQ378N', 'W2_F380W', 'W3_FQ387N', 'W3_F390M', 'W2_F390N', 'W3_F390W', 'W3_F395N', 'W3_F410M', 'W2_F410M', 'W3_FQ422M', 'A_F435W', 'W3_FQ436N', 'W3_FQ437N', 'W2_F437N', 'W3_F438W', 'W2_F439W', 'W2_F450W', 'W3_F467M', 'W2_F467M', 'W3_F469N', 'W2_F469N', 'A_F475W', 'W3_F475W', 'W3_F475X', 'W3_F487N', 'W2_F487N', 'W3_FQ492N', 'A_F502N', 'W3_F502N', 'W2_F502N', 'W3_FQ508N', 'W3_F547M', 'W2_F547M', 'A_F550M', 'A_F555W', 'W3_F555W', 'W2_F555W', 'W2_F569W', 'W3_FQ575N', 'W2_F588N', 'W3_F600LP', 'A_F606W', 'W3_F606W', 'W2_F606W', 'W3_FQ619N', 'W3_F621M', 'W2_F622W', 'A_F625W', 'W3_F625W', 'W3_F631N', 'W2_F631N', 'W3_FQ634N', 'W3_F645N', 'W3_F656N', 'W2_F656N', 'W3_F657N', 'A_F658N', 'W3_F658N', 'W2_F658N', 'A_F660N', 'W3_F665N', 'W3_F665N_F6', 'W3_FQ672N', 'W3_F673N', 'W2_F673N', 'W3_FQ674N', 'W2_F675W', 'W3_F680N', 'W3_F689M', 'W2_F702W', 'W3_FQ727N', 'W3_FQ750N', 'W3_F763M', 'A_F775W', 'W3_F775W', 'W2_F785LP', 'W2_F791W', 'A_F814W', 'W3_F814W', 'W2_F814W', 'W3_F845M', 'A_F850LP', 'W3_F850LP', 'W2_F850LP', 'W3_FQ889N', 'W3_FQ906N', 'W3_FQ924N', 'W3_FQ937N', 'W3_F953N', 'W2_F953N', 'W3_F098M', 'W3_G102', 'W2_F1042M', 'W3_F105W', 'W3_F110W', 'W3_F125W', 'W3_F126N', 'W3_F127M', 'W3_F128N', 'W3_F130N', 'W3_F132N', 'W3_F139M', 'W3_F140W', 'W3_G141', 'W3_F153M', 'W3_F160W', 'W3_F164N', 'W3_F167N']
name | type | description |
---|---|---|
str16 | str5 | str163 |
MatchID | long | identifier for the match |
MatchRA | float | right ascension coordinate of the match position |
MatchDec | float | declination coordinate of the match position |
DSigma | float | standard deviation of source positions in match |
AbsCorr | char | indicator of whether the match contains sources that are aligned to a standard catalog |
NumFilters | int | number of filters in match with sources detected in the aper2 aperture |
NumVisits | int | number of visits in match with sources detected in the aper2 aperture |
NumImages | int | number of Hubble Legacy Archive single filter, visit-combined (level 2) images in match with sources detected in the aper2 aperture |
StartTime | char | earliest start time of exposures in match with sources detected in the aper2 aperture |
StopTime | char | latest stop time of exposures in match with sources detected in the aper2 aperture |
StartMJD | float | modified Julian date (MJD) for earliest start time of exposures in match with sources detected in the aper2 aperture |
StopMJD | float | modified Julian date (MJD) for latest stop time of exposures in match with sources detected in the aper2 aperture |
TargetName | char | name of a target for an exposure in match |
CI | float | average normalized concentration index for sources detected in the aper2 aperture within the match |
CI_Sigma | float | standard deviation of normalized concentration index values for sources detected in the aper2 aperture within the match |
KronRadius | float | average Kron radius for sources detected in the aper2 aperture within the match |
KronRadius_Sigma | float | standard deviation of Kron radius values for sources detected in the aper2 aperture within the match |
Extinction | float | extinction, obtained from the NASA/IPAC Extragalactic Database (NED), along the line of sight to the match position |
SpectrumFlag | char | Y/N indicator of whether there is a spectrum in the Hubble Legacy Archive for this match. If the value is Y, then there is an entry in table SpecCat for the match. |
This is based on HSC Use Case #3, which shows an example of selecting objects from the HSC in portal. This is simple to do using the HSC API.
target = 'IC 1613'
ra, dec = resolve(target)
print(target,ra,dec)
IC 1613 16.19913 2.11778
This searches the summary table for objects within 0.5 degrees of the galaxy center that have at least 10 measurements in both ACS F475W and F814W.
# save typing a quoted list of columns
columns = """MatchID,MatchRA,MatchDec,NumFilters,NumVisits,NumImages,StartMJD,StopMJD,
A_F475W, A_F475W_N, A_F475W_MAD,
A_F814W, A_F814W_N, A_F814W_MAD""".split(",")
columns = [x.strip() for x in columns]
columns = [x for x in columns if x and not x.startswith('#')]
constraints = {'A_F475W_N.gte': 10, 'A_F814W_N.gte': 10}
t0 = time.time()
tab = hsccone(ra,dec,0.5,table="summary",release='v3',columns=columns,verbose=True,
format="table", **constraints)
print("{:.1f} s: retrieved data and converted to {}-row astropy table".format(time.time()-t0, len(tab)))
# clean up the output format
tab['A_F475W'].format = "{:.3f}"
tab['A_F475W_MAD'].format = "{:.3f}"
tab['A_F814W'].format = "{:.3f}"
tab['A_F814W_MAD'].format = "{:.3f}"
tab['MatchRA'].format = "{:.6f}"
tab['MatchDec'].format = "{:.6f}"
tab['StartMJD'].format = "{:.5f}"
tab['StopMJD'].format = "{:.5f}"
tab
https://catalogs.mast.stsci.edu/api/v0.1/hsc/v3/summary/magaper2.csv?A_F475W_N.gte=10&A_F814W_N.gte=10&ra=16.19913&dec=2.11778&radius=0.5&columns=%5BMatchID%2CMatchRA%2CMatchDec%2CNumFilters%2CNumVisits%2CNumImages%2CStartMJD%2CStopMJD%2CA_F475W%2CA_F475W_N%2CA_F475W_MAD%2CA_F814W%2CA_F814W_N%2CA_F814W_MAD%5D 7.7 s: retrieved data and converted to 18666-row astropy table
MatchID | MatchRA | MatchDec | NumFilters | NumVisits | NumImages | StartMJD | StopMJD | A_F475W | A_F475W_N | A_F475W_MAD | A_F814W | A_F814W_N | A_F814W_MAD |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
int64 | float64 | float64 | int64 | int64 | int64 | float64 | float64 | float64 | int64 | float64 | float64 | int64 | float64 |
86202333 | 16.132713 | 2.175139 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.860 | 12 | 0.024 | 26.385 | 12 | 0.051 |
86211369 | 16.122312 | 2.134637 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.378 | 12 | 0.016 | 24.610 | 12 | 0.033 |
1203016 | 16.125365 | 2.185955 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 26.265 | 12 | 0.054 | 25.517 | 12 | 0.020 |
1210439 | 16.110264 | 2.137299 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.344 | 12 | 0.012 | 25.742 | 12 | 0.027 |
1212513 | 16.109899 | 2.131498 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.608 | 12 | 0.007 | 22.291 | 12 | 0.009 |
1215326 | 16.104633 | 2.125625 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 26.198 | 12 | 0.029 | 26.442 | 12 | 0.074 |
1215632 | 16.097566 | 2.176860 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 24.938 | 12 | 0.012 | 24.312 | 12 | 0.008 |
41479013 | 16.101052 | 2.177409 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 20.822 | 12 | 0.012 | 21.441 | 12 | 0.019 |
41479950 | 16.131446 | 2.176147 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 24.719 | 12 | 0.025 | 25.444 | 12 | 0.031 |
41481792 | 16.107746 | 2.132426 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 26.189 | 12 | 0.057 | 26.589 | 12 | 0.115 |
41483635 | 16.121088 | 2.132010 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 24.751 | 12 | 0.010 | 24.536 | 12 | 0.025 |
41491470 | 16.122451 | 2.154569 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 24.497 | 12 | 0.011 | 23.418 | 12 | 0.013 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
68631503 | 16.126512 | 2.151951 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.770 | 12 | 0.032 | 26.136 | 12 | 0.040 |
68636930 | 16.104477 | 2.127323 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 26.048 | 12 | 0.052 | 25.585 | 12 | 0.018 |
7486910 | 16.108241 | 2.161547 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.506 | 12 | 0.024 | 26.033 | 12 | 0.041 |
65741429 | 16.138380 | 2.142784 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 25.622 | 12 | 0.035 | 24.735 | 12 | 0.056 |
65745001 | 16.089381 | 2.173680 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.272 | 12 | 0.005 | 21.691 | 12 | 0.003 |
108047285 | 16.145230 | 2.156788 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.700 | 12 | 0.005 | 21.243 | 12 | 0.003 |
108048053 | 16.150571 | 2.142590 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 25.342 | 12 | 0.091 | 24.544 | 12 | 0.031 |
108051851 | 16.128325 | 2.149198 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 26.445 | 12 | 0.063 | 25.702 | 12 | 0.061 |
108054963 | 16.095892 | 2.173002 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.380 | 12 | 0.014 | 21.612 | 12 | 0.010 |
108055849 | 16.117681 | 2.131627 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 26.614 | 12 | 0.034 | 25.778 | 12 | 0.053 |
79220915 | 16.135118 | 2.137768 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 24.942 | 12 | 0.017 | 23.967 | 12 | 0.030 |
79229073 | 16.130665 | 2.135877 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 25.271 | 12 | 0.019 | 24.593 | 12 | 0.018 |
79231245 | 16.134299 | 2.162190 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 25.497 | 12 | 0.020 | 24.954 | 12 | 0.011 |
We mark the galaxy center as well. Note that this field is in the outskirts of IC 1613. The 0.5 search radius (which is the maximum allowed in the API) allows finding these objects.
pylab.rcParams.update({'font.size': 16})
pylab.figure(1,(10,10))
pylab.plot(tab['MatchRA'], tab['MatchDec'], 'bo', markersize=1,
label='{} HSC measurements'.format(len(tab)))
pylab.plot(ra,dec,'rx',label=target,markersize=10)
pylab.gca().invert_xaxis()
pylab.gca().set_aspect('equal')
pylab.xlabel('RA [deg]')
pylab.ylabel('Dec [deg]')
pylab.legend(loc='best')
<matplotlib.legend.Legend at 0x7f93501f5e50>
The median absolute deviation is measured among the ~12 magnitude measurements in the catalog. Some scatter is expected from noise (which increases for fainter objects). Objects with MAD values that are high are likely to be variable.
Select variable objects that are not too faint.
wvar = np.where((tab['A_F475W_MAD']>0.1) & (tab['A_F475W']<24) & (tab['A_F475W']>21))[0]
pylab.rcParams.update({'font.size': 16})
pylab.figure(1,(10,10))
pylab.plot(tab['A_F475W'], tab['A_F475W_MAD'], 'bo', markersize=2,
label='{} HSC measurements near {}'.format(len(tab),target))
pylab.plot(tab['A_F475W'][wvar], tab['A_F475W_MAD'][wvar], 'ro', markersize=5,
label='{} variable candidates'.format(len(wvar)))
pylab.xlabel('A_F475W [mag]')
pylab.ylabel('A_F475W_MAD [mag]')
pylab.legend(loc='best')
<matplotlib.legend.Legend at 0x7f934033a400>
Note that these objects are generally located in the Cepheid instability strip.
pylab.rcParams.update({'font.size': 16})
pylab.figure(1,(10,10))
b_minus_i = tab['A_F475W'] - tab['A_F814W']
pylab.plot(b_minus_i, tab['A_F475W'], 'bo', markersize=2,
label='{} HSC measurements near {}'.format(len(tab),target))
pylab.plot(b_minus_i[wvar], tab['A_F475W'][wvar], 'ro', markersize=5,
label='{} variable candidates'.format(len(wvar)))
pylab.ylabel('A_F475W [mag]')
pylab.xlabel('A_F475W - A_F814W [mag]')
pylab.gca().invert_yaxis()
pylab.legend(loc='best')
<matplotlib.legend.Legend at 0x7f9368465bb0>
Select the most variable object as an example.
wvar = wvar[np.argsort(-tab['A_F475W_MAD'][wvar])]
iselect = wvar[0]
print("MatchID {} B = {:.3f} B-I = {:.3f}".format(
tab['MatchID'][iselect], tab['A_F475W'][iselect], b_minus_i[iselect]))
tab[wvar]
MatchID 80189155 B = 22.451 B-I = 0.450
MatchID | MatchRA | MatchDec | NumFilters | NumVisits | NumImages | StartMJD | StopMJD | A_F475W | A_F475W_N | A_F475W_MAD | A_F814W | A_F814W_N | A_F814W_MAD |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
int64 | float64 | float64 | int64 | int64 | int64 | float64 | float64 | float64 | int64 | float64 | float64 | int64 | float64 |
80189155 | 16.140740 | 2.155288 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.451 | 12 | 0.294 | 22.001 | 12 | 0.198 |
8200488 | 16.144772 | 2.152338 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.202 | 12 | 0.260 | 21.768 | 12 | 0.188 |
66012678 | 16.135134 | 2.154740 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.559 | 12 | 0.253 | 22.101 | 12 | 0.192 |
63078526 | 16.105513 | 2.155580 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.317 | 12 | 0.227 | 22.897 | 12 | 0.138 |
89909862 | 16.117180 | 2.168810 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.733 | 12 | 0.224 | 22.545 | 12 | 0.099 |
92119358 | 16.136563 | 2.182817 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.347 | 12 | 0.213 | 23.234 | 12 | 0.131 |
66980564 | 16.125611 | 2.135287 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.732 | 12 | 0.194 | 22.365 | 12 | 0.138 |
95722356 | 16.133030 | 2.175638 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.359 | 12 | 0.180 | 22.921 | 12 | 0.129 |
68356083 | 16.095709 | 2.147460 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.378 | 12 | 0.176 | 22.981 | 12 | 0.109 |
45786610 | 16.121375 | 2.133853 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.901 | 12 | 0.174 | 22.557 | 12 | 0.131 |
59681000 | 16.146936 | 2.142438 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 23.701 | 12 | 0.169 | 23.278 | 12 | 0.081 |
37770720 | 16.124833 | 2.176284 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.513 | 12 | 0.168 | 23.088 | 12 | 0.153 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
77799595 | 16.111191 | 2.181553 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.809 | 12 | 0.149 | 23.614 | 12 | 0.087 |
2773895 | 16.117561 | 2.162184 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.484 | 12 | 0.139 | 23.079 | 12 | 0.098 |
86143477 | 16.137353 | 2.165975 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 22.255 | 12 | 0.135 | 21.965 | 12 | 0.049 |
69790109 | 16.141284 | 2.152881 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.635 | 12 | 0.133 | 22.138 | 12 | 0.071 |
100437228 | 16.111310 | 2.160908 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.382 | 12 | 0.123 | 22.914 | 12 | 0.070 |
30855111 | 16.105925 | 2.157603 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.781 | 12 | 0.117 | 22.698 | 12 | 0.056 |
70217468 | 16.107142 | 2.178161 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.804 | 12 | 0.116 | 23.428 | 12 | 0.116 |
9510698 | 16.137963 | 2.141027 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.343 | 12 | 0.114 | 23.101 | 12 | 0.080 |
13317380 | 16.118322 | 2.152817 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.599 | 12 | 0.109 | 23.169 | 12 | 0.091 |
17240899 | 16.139667 | 2.153597 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 22.761 | 12 | 0.105 | 22.195 | 12 | 0.073 |
105545986 | 16.144336 | 2.156262 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.160 | 12 | 0.104 | 22.941 | 12 | 0.138 |
66716166 | 16.132260 | 2.163512 | 3 | 14 | 26 | 53965.29153 | 57009.86262 | 23.075 | 12 | 0.104 | 22.864 | 12 | 0.075 |
63755650 | 16.095356 | 2.137338 | 2 | 12 | 24 | 53965.29153 | 53967.71941 | 22.729 | 12 | 0.103 | 22.442 | 12 | 0.062 |
Get column metadata for detailed observation table (which has time-dependent magnitudes).
meta = hscmetadata("detailed")
print(len(meta),"columns in detailed")
pprint(meta['name'].tolist(), compact=True)
39 columns in detailed ['CatID', 'MatchID', 'MemID', 'SourceID', 'ImageID', 'Det', 'MatchRA', 'MatchDec', 'SourceRA', 'SourceDec', 'D', 'DSigma', 'AbsCorr', 'XImage', 'YImage', 'ImageName', 'Instrument', 'Mode', 'Detector', 'Aperture', 'ExposureTime', 'StartTime', 'StopTime', 'StartMJD', 'StopMJD', 'WaveLength', 'Filter', 'TargetName', 'FluxAper2', 'MagAper2', 'MagAuto', 'PropID', 'CI', 'KronRadius', 'Flags', 'HTMID', 'X', 'Y', 'Z']
columns = """MatchID,SourceID,StartMJD,Detector,Filter,MagAper2,Flags,ImageName""".split(",")
columns = [x.strip() for x in columns]
columns = [x for x in columns if x and not x.startswith('#')]
constraints = {'MatchID': tab['MatchID'][iselect], 'Detector': 'ACS/WFC'}
t0 = time.time()
f475 = hscsearch(table="detailed",release='v3',columns=columns,Filter='F475W',
format="table", **constraints)
f814 = hscsearch(table="detailed",release='v3',columns=columns,Filter='F814W',
format="table", **constraints)
print("{:.1f} s: retrieved data and converted to {} (F475W) and {} (F814W) row astropy tables".format(time.time()-t0, len(f475), len(f814)))
f475.sort('StartMJD')
f814.sort('StartMJD')
f475['MagAper2'].format = "{:.3f}"
f475['StartMJD'].format = "{:.5f}"
f814['MagAper2'].format = "{:.3f}"
f814['StartMJD'].format = "{:.5f}"
f475
0.6 s: retrieved data and converted to 12 (F475W) and 12 (F814W) row astropy tables
MatchID | SourceID | StartMJD | Detector | Filter | MagAper2 | Flags | ImageName |
---|---|---|---|---|---|---|---|
int64 | int64 | float64 | str7 | str5 | float64 | int64 | str26 |
80189155 | 4000999062305 | 53965.29153 | ACS/WFC | F475W | 22.192 | 0 | hst_10505_07_acs_wfc_f475w |
80189155 | 4000992888001 | 53965.42473 | ACS/WFC | F475W | 22.246 | 0 | hst_10505_08_acs_wfc_f475w |
80189155 | 4001095116962 | 53965.55794 | ACS/WFC | F475W | 22.376 | 0 | hst_10505_09_acs_wfc_f475w |
80189155 | 4000922680735 | 53965.69115 | ACS/WFC | F475W | 22.552 | 0 | hst_10505_10_acs_wfc_f475w |
80189155 | 4001042276145 | 53966.29057 | ACS/WFC | F475W | 22.705 | 0 | hst_10505_11_acs_wfc_f475w |
80189155 | 4001225221390 | 53966.42377 | ACS/WFC | F475W | 22.802 | 0 | hst_10505_12_acs_wfc_f475w |
80189155 | 4000895760719 | 53966.55698 | ACS/WFC | F475W | 22.779 | 0 | hst_10505_13_acs_wfc_f475w |
80189155 | 4000814317863 | 53966.69019 | ACS/WFC | F475W | 22.801 | 0 | hst_10505_14_acs_wfc_f475w |
80189155 | 4000830929643 | 53967.22301 | ACS/WFC | F475W | 22.526 | 0 | hst_10505_15_acs_wfc_f475w |
80189155 | 4000859171115 | 53967.35622 | ACS/WFC | F475W | 21.522 | 0 | hst_10505_16_acs_wfc_f475w |
80189155 | 4001162870082 | 53967.48942 | ACS/WFC | F475W | 21.449 | 0 | hst_10505_17_acs_wfc_f475w |
80189155 | 4000926592856 | 53967.62263 | ACS/WFC | F475W | 21.769 | 0 | hst_10505_18_acs_wfc_f475w |
The light curves appear well-behaved and are closely correlated in the two filters.
pylab.rcParams.update({'font.size': 16})
pylab.figure(1,(10,10))
pylab.subplot(211)
pylab.plot(f475['StartMJD'], f475['MagAper2'], 'bo', label='ACS/WFC F475W')
pylab.gca().invert_yaxis()
pylab.ylabel('F475W [mag]')
pylab.legend(loc='best')
xlim = pylab.xlim()
pylab.subplot(212)
pylab.plot(f814['StartMJD'], f814['MagAper2'], 'ro', label='ACS/WFC F814W')
pylab.gca().invert_yaxis()
pylab.ylabel('F814W [mag]')
pylab.xlabel('MJD [days]')
pylab.xlim(xlim)
pylab.legend(loc='best')
<matplotlib.legend.Legend at 0x7f938080cfd0>
Get HLA F475W cutout images for the example variable. The get_hla_cutout
function reads a single cutout image (as a JPEG grayscale image) and returns a PIL image object. See the documentation on the fitscut image cutout service for more information on the web service being used.
Examination of the images can be useful to identified cosmic-ray contamination and other possible image artifacts. In this case, no issues are seen, so the light curve is likely to be reliable.
def get_hla_cutout(imagename,ra,dec,size=33,autoscale=99.5,asinh=1,zoom=1):
"""Get JPEG cutout for an image"""
url = "https://hla.stsci.edu/cgi-bin/fitscut.cgi"
r = requests.get(url, params=dict(ra=ra, dec=dec, size=size,
format="jpeg", red=imagename, autoscale=autoscale, asinh=asinh, zoom=zoom))
im = Image.open(BytesIO(r.content))
return im
# sort images by magnitude from faintest to brightest
isort = np.argsort(-f475['MagAper2'])
imagename = f475['ImageName'][isort]
mag = f475['MagAper2'][isort]
mjd = f475['StartMJD'][isort]
nim = len(imagename)
ncols = 4 # images per row
nrows = (nim+ncols-1)//ncols
imsize = 15
mra = tab['MatchRA'][iselect]
mdec = tab['MatchDec'][iselect]
pylab.rcParams.update({"font.size":11})
pylab.figure(1,(15, (15/ncols)*nrows))
t0 = time.time()
for k in range(nim):
im1 = get_hla_cutout(imagename[k],mra,mdec,size=imsize)
pylab.subplot(nrows,ncols,k+1)
pylab.imshow(im1,origin="upper",cmap="gray")
pylab.title('{:.5f} f475w={:.3f}'.format(mjd[k],mag[k]))
if ((k+1) % 10)==0:
print("{:.1f} s: finished {} of {}".format(time.time()-t0,k+1,nim))
pylab.tight_layout()
print("{:.1f} s: finished {}".format(time.time()-t0,nim))
9.2 s: finished 10 of 12 11.1 s: finished 12