Using the nexsciTAP Server with the PyVO Client to Access Data From KOA In Asynchronous Mode

The nexsciTAP server

The NASA Exoplanet Science Institute (NExScI) (visit https://nexsci.caltech.edu) has developed a Python-based server to implement an API that complies with the Virtual Observatory (VO) Table Access Protocol(TAP) version 1.1 (September 2019) (http://ivoa.net/documents/TAP/20190927/index.html), a standard recommended by the International Virtual Observatory alliance (IVOA) (http://ivoa.net).

The TAP API enables a rich variety of searches against tabular data, includung cone, box or all-sky searches, temporal searches, combinations of spatial searches and temporal searches, searches against instrumental attributes and program attributes.

This tutorial supports demonstrates how to use the PyVO client to perform asynchronous TAP-based queries for public raw science and calibation data acquired with the Echellette Spectrograph and Imager (ESI); these data are hosted at the Keck Observatory Archive (KOA; https://koa.ipac.caltech.edu).

Requirements

This tutorial uses PyVO version 1.1.1, and can be installed from PyPI:

$ pip install --upgrade PyVO

The tutorial requires Python 3.6 (or above), plus the table read and write functions from Astropy. We have tested with Astropy 4.0.1, but any version should work. We recommend using the Ananconda Python distribution.

A note on output records

The number of records returned here may differ from those returned here because new data are released daily.

Version 1.0 (March, 2021)

Set up

In [1]:
from pyvo.dal import tap 
koa = tap.TAPService("https://koa.ipac.caltech.edu/TAP")

import sys
import os
import time

Query by date

In [4]:
sql = "select koaid, filehand from koa_esi where koaid like '%20150902%' "

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsAS = job.fetch_result()
print(resultsAS)

# write output file
table=resultsAS.to_table()
table.write ('./table_select_AStime.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_ohf0cgjx
job_id:  tap_ohf0cgjx
phase:   PENDING
phase:   COMPLETED
<Table length=13>
        koaid                                filehand                     
        object                                object                      
---------------------- ---------------------------------------------------
ES.20150902.10478.fits /koadata36/ESI/20150902/lev0/ES.20150902.10478.fits
ES.20150902.10550.fits /koadata36/ESI/20150902/lev0/ES.20150902.10550.fits
ES.20150902.45958.fits /koadata36/ESI/20150902/lev0/ES.20150902.45958.fits
ES.20150902.46025.fits /koadata36/ESI/20150902/lev0/ES.20150902.46025.fits
ES.20150902.46101.fits /koadata36/ESI/20150902/lev0/ES.20150902.46101.fits
ES.20150902.46168.fits /koadata36/ESI/20150902/lev0/ES.20150902.46168.fits
ES.20150902.46410.fits /koadata36/ESI/20150902/lev0/ES.20150902.46410.fits
ES.20150902.85368.fits /koadata36/ESI/20150903/lev0/ES.20150902.85368.fits
ES.20150902.85427.fits /koadata36/ESI/20150903/lev0/ES.20150902.85427.fits
ES.20150902.85487.fits /koadata36/ESI/20150903/lev0/ES.20150902.85487.fits
ES.20150902.85546.fits /koadata36/ESI/20150903/lev0/ES.20150902.85546.fits
ES.20150902.85605.fits /koadata36/ESI/20150903/lev0/ES.20150902.85605.fits
ES.20150902.85664.fits /koadata36/ESI/20150903/lev0/ES.20150902.85664.fits

PyVO by default returns results in VOTable format. Write to IPAC ASCII and CSV format for storage.

In [5]:
# IPAC ASCII
table=resultsAS.to_table()
table.write ('./table_ipacasciiAS_time.tbl',format='ascii.ipac', \
             overwrite=True)

# CSV
table_csv=resultsAS.to_table()
table.write ('./table_csvAS_time.csv',format='csv',overwrite=True)

Select all keywords for data acquired on UT Date

In [6]:
sql = "select * from koa_esi where koaid like '%20150902%' "
job = koa.submit_job(sql)

print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsALL= job.fetch_result()

print(resultsALL)

# write output file in VTtable format
table_selectall=resultsALL.to_table()
table_selectall.write ('./table_select_asynchALL.vot', \
                        format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_azgmzkzf
job_id:  tap_azgmzkzf
phase:   PENDING
phase:   COMPLETED
<Table length=13>
        koaid                ofname      filesize_mb ...    z      spt_ind 
        object               object        float64   ... float64    int32  
---------------------- ----------------- ----------- ... -------- ---------
ES.20150902.10478.fits e150902_0001.fits          -- ... 0.707107 233211302
ES.20150902.10550.fits e150902_0002.fits          -- ... 0.707107 233211302
ES.20150902.45958.fits e150902_0003.fits          -- ... 0.707107 233211302
ES.20150902.46025.fits e150902_0004.fits          -- ... 0.707107 233211302
ES.20150902.46101.fits e150902_0005.fits          -- ... 0.707107 233211302
ES.20150902.46168.fits e150902_0006.fits          -- ... 0.707107 233211302
ES.20150902.46410.fits e150902_0007.fits          -- ... 0.707107 233211302
ES.20150902.85368.fits e150903_0001.fits          -- ... 0.710322 223311221
ES.20150902.85427.fits e150903_0002.fits          -- ... 0.710322 223311221
ES.20150902.85487.fits e150903_0003.fits          -- ... 0.710322 223311221
ES.20150902.85546.fits e150903_0004.fits          -- ... 0.710322 223311221
ES.20150902.85605.fits e150903_0005.fits          -- ... 0.710322 223311221
ES.20150902.85664.fits e150903_0006.fits          -- ... 0.710322 223311221

Select columns on UT date

In [7]:
sql = "select koaid, filehand from koa_esi where koaid like '%20150902%' "

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsASK = job.fetch_result()

print(resultsASK)

## write output file
table=resultsASK.to_table()
table.write ('./table_asynch_cols.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_wx7pb8g3
job_id:  tap_wx7pb8g3
phase:   PENDING
phase:   COMPLETED
<Table length=13>
        koaid                                filehand                     
        object                                object                      
---------------------- ---------------------------------------------------
ES.20150902.10478.fits /koadata36/ESI/20150902/lev0/ES.20150902.10478.fits
ES.20150902.10550.fits /koadata36/ESI/20150902/lev0/ES.20150902.10550.fits
ES.20150902.45958.fits /koadata36/ESI/20150902/lev0/ES.20150902.45958.fits
ES.20150902.46025.fits /koadata36/ESI/20150902/lev0/ES.20150902.46025.fits
ES.20150902.46101.fits /koadata36/ESI/20150902/lev0/ES.20150902.46101.fits
ES.20150902.46168.fits /koadata36/ESI/20150902/lev0/ES.20150902.46168.fits
ES.20150902.46410.fits /koadata36/ESI/20150902/lev0/ES.20150902.46410.fits
ES.20150902.85368.fits /koadata36/ESI/20150903/lev0/ES.20150902.85368.fits
ES.20150902.85427.fits /koadata36/ESI/20150903/lev0/ES.20150902.85427.fits
ES.20150902.85487.fits /koadata36/ESI/20150903/lev0/ES.20150902.85487.fits
ES.20150902.85546.fits /koadata36/ESI/20150903/lev0/ES.20150902.85546.fits
ES.20150902.85605.fits /koadata36/ESI/20150903/lev0/ES.20150902.85605.fits
ES.20150902.85664.fits /koadata36/ESI/20150903/lev0/ES.20150902.85664.fits

Select maximum number of records to return from a query

In [10]:
sql = "select koaid, filehand, frameno from koa_esi where koaid like '%20150902%'"
job = koa.submit_job(sql,maxrec=10)

print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsASK10 = job.fetch_result( )

print(resultsASK10)

## write output file
table=resultsASK10.to_table()
table.write ('./table_asynch_max10.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_6m3_9nxa
job_id:  tap_6m3_9nxa
phase:   PENDING
phase:   COMPLETED
<Table length=13>
        koaid          ... frameno
        object         ...  int32 
---------------------- ... -------
ES.20150902.10478.fits ...       1
ES.20150902.10550.fits ...       2
ES.20150902.45958.fits ...       3
ES.20150902.46025.fits ...       4
ES.20150902.46101.fits ...       5
ES.20150902.46168.fits ...       6
ES.20150902.46410.fits ...       7
ES.20150902.85368.fits ...       1
ES.20150902.85427.fits ...       2
ES.20150902.85487.fits ...       3
ES.20150902.85546.fits ...       4
ES.20150902.85605.fits ...       5
ES.20150902.85664.fits ...       6

Query records by time range

In [11]:
sql="select koaid, filehand from koa_esi \
   where (utdatetime >= to_date('2015-09-01 00:00:00', 'yyyy-mm-dd HH24:MI:SS') \
   and utdatetime <= to_date('2015-09-30 23:59:59', 'yyyy-mm-dd HH24:MI:SS'))"


job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsDATERANGE = job.fetch_result()
print(resultsDATERANGE)

## write to output file
table=resultsDATERANGE.to_table()
table.write ('./table_asynch_daterange.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_dh0ohn9v
job_id:  tap_dh0ohn9v
phase:   PENDING
phase:   COMPLETED
<Table length=225>
        koaid                                filehand                     
        object                                object                      
---------------------- ---------------------------------------------------
ES.20150902.10478.fits /koadata36/ESI/20150902/lev0/ES.20150902.10478.fits
ES.20150902.10550.fits /koadata36/ESI/20150902/lev0/ES.20150902.10550.fits
ES.20150902.45958.fits /koadata36/ESI/20150902/lev0/ES.20150902.45958.fits
ES.20150902.46025.fits /koadata36/ESI/20150902/lev0/ES.20150902.46025.fits
ES.20150902.46101.fits /koadata36/ESI/20150902/lev0/ES.20150902.46101.fits
ES.20150902.46168.fits /koadata36/ESI/20150902/lev0/ES.20150902.46168.fits
ES.20150902.46410.fits /koadata36/ESI/20150902/lev0/ES.20150902.46410.fits
ES.20150902.85368.fits /koadata36/ESI/20150903/lev0/ES.20150902.85368.fits
ES.20150902.85427.fits /koadata36/ESI/20150903/lev0/ES.20150902.85427.fits
ES.20150902.85487.fits /koadata36/ESI/20150903/lev0/ES.20150902.85487.fits
                   ...                                                 ...
ES.20150911.26693.fits /koadata36/ESI/20150911/lev0/ES.20150911.26693.fits
ES.20150911.35455.fits /koadata36/ESI/20150911/lev0/ES.20150911.35455.fits
ES.20150911.42470.fits /koadata36/ESI/20150911/lev0/ES.20150911.42470.fits
ES.20150911.44332.fits /koadata36/ESI/20150911/lev0/ES.20150911.44332.fits
ES.20150911.46194.fits /koadata36/ESI/20150911/lev0/ES.20150911.46194.fits
ES.20150911.48056.fits /koadata36/ESI/20150911/lev0/ES.20150911.48056.fits
ES.20150911.50078.fits /koadata36/ESI/20150911/lev0/ES.20150911.50078.fits
ES.20150911.51339.fits /koadata36/ESI/20150911/lev0/ES.20150911.51339.fits
ES.20150911.52604.fits /koadata36/ESI/20150911/lev0/ES.20150911.52604.fits
ES.20150911.53867.fits /koadata36/ESI/20150911/lev0/ES.20150911.53867.fits

Query by program ID

In [12]:
sql=("select koaid, filehand, progid from \
      koa_esi where (progid = 'K197E')")

job = koa.submit_job(sql)
print('url:    ', job.url)

print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsPROGID= job.fetch_result( )

print(resultsPROGID)

## write to output file
table_progID=resultsPROGID.to_table()
table.write ('./table_progID.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_rqnif7jd
job_id:  tap_rqnif7jd
phase:   PENDING
phase:   COMPLETED
<Table length=105>
        koaid          ... progid
        object         ... object
---------------------- ... ------
ES.20140724.08809.fits ...  K197E
ES.20140724.09553.fits ...  K197E
ES.20140724.10762.fits ...  K197E
ES.20140724.10811.fits ...  K197E
ES.20140724.11148.fits ...  K197E
ES.20140724.11286.fits ...  K197E
ES.20140724.11391.fits ...  K197E
ES.20140724.11496.fits ...  K197E
ES.20140724.11615.fits ...  K197E
ES.20140724.11721.fits ...  K197E
                   ... ...    ...
ES.20140724.33833.fits ...  K197E
ES.20140724.33919.fits ...  K197E
ES.20140724.34019.fits ...  K197E
ES.20140724.34713.fits ...  K197E
ES.20140724.35396.fits ...  K197E
ES.20140724.36090.fits ...  K197E
ES.20140724.36465.fits ...  K197E
ES.20140724.36862.fits ...  K197E
ES.20140724.36948.fits ...  K197E
ES.20140724.37034.fits ...  K197E
In [13]:
sql=("select koaid, filehand, ra, dec from koa_esi \
    where contains(point('icrs', ra, dec), circle('icrs',255.03913 -11.82214 1.0))   = 1")

    
job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsSPA= job.fetch_result( )

print(resultsSPA)

# write to output file
table=resultsSPA.to_table()
table.write ('./table_asynch_spatial_cone.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_lephmnd4
job_id:  tap_lephmnd4
phase:   PENDING
phase:   COMPLETED
<Table length=8>
        koaid          ...    dec   
        object         ...  float64 
---------------------- ... ---------
ES.20140724.19862.fits ... -11.82214
ES.20140724.19954.fits ... -11.82214
ES.20140724.20187.fits ... -11.82214
ES.20140724.20277.fits ... -11.82214
ES.20140724.20549.fits ... -11.82214
ES.20140724.20649.fits ... -11.82214
ES.20140724.20925.fits ... -11.82214
ES.20140724.21025.fits ... -11.82214
In [14]:
sql=("select koaid, filehand, ra, dec from koa_esi where \
     contains(point('icrs', ra, dec), \
     box('icrs',23.48, 30.60,1.0,120)) = 1")

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsSPA_BOX= job.fetch_result( )

print(resultsSPA_BOX)

## write to output file
table=resultsSPA_BOX.to_table()
table.write ('./table_spatial_Box.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_4i9mztcj
job_id:  tap_4i9mztcj
phase:   PENDING
phase:   COMPLETED
<Table length=1355>
        koaid          ...   dec   
        object         ... float64 
---------------------- ... --------
ES.19990831.33124.fits ... 89.72169
ES.19990831.33223.fits ... 89.72169
ES.19990831.33424.fits ... 89.72169
ES.19990831.33559.fits ... 89.72169
ES.19990831.33822.fits ... 89.72169
ES.19990831.34017.fits ... 89.72169
ES.19990831.34113.fits ... 89.72169
ES.19990831.34210.fits ... 89.72169
ES.19990831.34307.fits ... 89.72169
ES.19990831.35315.fits ... 89.72169
                   ... ...      ...
ES.20190506.77915.fits ...    90.01
ES.20190506.78101.fits ...    90.01
ES.20190506.78161.fits ...    90.01
ES.20190506.78213.fits ...    90.01
ES.20190506.78268.fits ...    90.01
ES.20190506.78320.fits ...    90.01
ES.20190506.78374.fits ...    90.01
ES.20190506.78428.fits ...    90.01
ES.20190506.78482.fits ...    90.01
ES.20190506.78535.fits ...    90.01
In [15]:
sql=("select koaid, filehand, ra, dec from koa_esi where \
    contains(point('icrs', ra, dec), \
    polygon('icrs',209.80225,53.34894,209.80225,55.34894,211.80225,54.34894)) = 1")

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

resultsSPA_POLY= job.fetch_result( )

print(resultsSPA_POLY)

## write to output file
table=resultsSPA_POLY.to_table()
table.write ('./table_spatial_P.vot',format='votable',overwrite=True)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_wy791zzj
job_id:  tap_wy791zzj
phase:   PENDING
phase:   COMPLETED
<Table length=2>
        koaid          ...   dec   
        object         ... float64 
---------------------- ... --------
ES.20120315.48168.fits ... 54.41872
ES.20120315.49127.fits ... 54.41872

Count number of records in a time range

In [ ]:
sql=("select count(*) from koa_esi where \
     (utdatetime >= to_date('2015-09-01 00:00:00', 'yyyy-mm-dd HH24:MI:SS') and  \
     utdatetime <= to_date('2015-09-30 23:59:59', 'yyyy-mm-dd HH24:MI:SS'))")

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
    time.sleep(2)
    
print('phase:  ', job.phase)

results_count= job.fetch_result( )

print(results_count)

Count total number of records

In [23]:
sql="select count(*) as total from koa_esi"

job = koa.submit_job(sql)
print('url:    ', job.url)
print('job_id: ', job.job_id)
print('phase:  ', job.phase)

job.run()

while job.phase == 'EXECUTING':
      time.sleep(2)
    
print('phase:  ', job.phase)

results_count= job.fetch_result( )

print(results_count)
url:     https://koa.ipac.caltech.edu/TAP/async/tap_wpqra9tg
job_id:  tap_wpqra9tg
phase:   PENDING
phase:   COMPLETED
<Table length=1>
total
int32
-----
69477

Visit KOA at https://koa.ipac.caltech.edu.

The Keck Observatory Archive (KOA) is a collaboration between the NASA Exoplanet Science Institute (NExScI) and the W. M. Keck Observatory (WMKO). NExScI is sponsored by NASA's Exoplanet Exploration Program, and operated by the California Institute of Technology in coordination with the Jet Propulsion Laboratory (JPL).

Need help? Submit your questions to the KOA Help Desk at https://koa.ipac.caltech.edu/cgi-bin/Helpdesk/nph-genTicketForm?projname=KOA