102.2. Consultas de catalogos con TAP#
102.2. Consultas de catálogos con TAP¶
Para la Plataforma Científica de Rubin en data.lsst.cloud.
Divulgación de Datos: Vista Previa de Datos 1
Tamaño del contenedor (Container size): large
Versión de las Pipelines Científicas de LSST: r29.2.0
Última verificación de ejecución: 2025-11-10
Repositorio: github.com/lsst/tutorial-notebooks
DOI: 10.11578/rubin/dc.20250909.20
Objetivo de aprendizaje: Cómo ejecutar consultas TAP ADQL complejas sobre catálogos.
Productos de datos LSST: Tabla Object
Paquetes: lsst.rsp.get_tap_service
Créditos: Desarrollado originalmente por el equipo científico de la comunidad de Rubin. Por favor, considerar reconocer su trabajo si este notebook se utiliza para la preparación de artículos de revistas, lanzamientos de software u otros notebooks.
Soporte: Se invita a toda la comunidad a hacer preguntas o plantear problemas en la Categoría de asistencia del Foro de la Comunidad de Rubin. El equipo de Rubin responderá a todas las preguntas publicadas allí.
1. Introducción¶
TAP proporciona acceso estandarizado a datos de catálogos para exploración, búsqueda y recuperación. La documentación completa de TAP es proporcionada por la Alianza Internacional de Observatorios Virtuales (IVOA - International Virtual Observatory Alliance).
ADQL (Astronomy Data Query Language - Lenguaje de Consulta de Datos Astronómicos) es similar a SQL (Structured Query Language - Lenguaje de Consulta Estructurado). La documentación de ADQL incluye más información sobre sintaxis y palabras clave. No toda la funcionalidad de ADQL está soportada todavía en la fase de vista previa del RSP.
Este tutorial demuestra opciones para manipular y restringir columnas y para dar formato a los conjuntos de datos recuperados con ADQL.
Tutoriales relacionados: Los demás tutoriales de nivel 100 en esta serie presentan los conceptos básicos de TAP. Los tutoriales de nivel 200 describen el contenido de los datos del catálogo e incluyen consultas de ejemplo para cada uno.
import numpy as np
from lsst.rsp import get_tap_service
1.2. Definir parámetros¶
Instanciar el servicio TAP.
service = get_tap_service("tap")
assert service is not None
2. Manipular columnas¶
Comenzar con una consulta básica que ejecute una búsqueda cónica en la tabla Object para objetos a distancias de 0.01 grados de las coordenadas cerca del centro del campo ECDFS, RA, Dec = 53, -28 grados.
query = """SELECT coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
2.1. Renombrar columnas¶
Las columnas pueden ser renombradas usando la cláusula AS en la consulta.
Renombrar coord_ra como ra, y coord_dec como dec.
query = """SELECT coord_ra AS ra, coord_dec AS dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT coord_ra AS ra, coord_dec AS dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
Ejecutar la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
La fase del trabajo es COMPLETED
Mostrar que las columnas fueron renombradas.
results.colnames
['ra', 'dec']
job.delete()
del query, results
2.2. Aplicar funciones ADQL¶
Se puede aplicar una variedad de funciones matemáticas, trigonométricas y geométricas a las columnas, y los resultados se almacenarán como columnas en el arreglo devuelto. Consultar la documentación de ADQL para ver la lista completa.
Utilizar la misma consulta que antes, pero convertir las coordenadas de grados a radianes
y renombrar las columnas como ra_radians y dec_radians.
Recuperar también la distancia angular bidimensional en el cielo entre cada objeto y las coordenadas de búsqueda y almacenarla como distance.
query = """SELECT RADIANS(coord_ra) AS ra_rad,
RADIANS(coord_dec) AS dec_rad,
DISTANCE(POINT('ICRS', coord_ra, coord_dec),
POINT('ICRS', 53, -28)) AS distance
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT RADIANS(coord_ra) AS ra_rad,
RADIANS(coord_dec) AS dec_rad,
DISTANCE(POINT('ICRS', coord_ra, coord_dec),
POINT('ICRS', 53, -28)) AS distance
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
La fase del trabajo es COMPLETED
Mostrar sólo la primera fila de la tabla.
results[0]
| ra_rad | dec_rad | distance |
|---|---|---|
| float64 | float64 | float64 |
| 0.9250236455912983 | -0.488863082199624 | 0.009791465987706714 |
job.delete()
del query, results
2.3. Convertir flujos a magnitudes¶
Las mediciones fotométricas de objetos y fuentes del LSST se almacenan en los catálogos como flujos en unidades de nanoJanskys (nJy).
La conversión de nJy a magnitud AB es $m_{\rm AB} = -2.5 \log(f_{\rm nJy}) + 31.4$.
Advertencia: Los flujos de imágenes diferenciales y los flujos de fotometría forzada pueden ser negativos; se debe tener cuidado con las conversiones a magnitudes.
Existen funciones para devolver flujos (y errores) como magnitudes AB:
scisql_nanojanskyToAbMagscisql_nanojanskyToAbMagSigma
El catálogo Object tiene columnas de magnitudes correspondientes a los flujos PSF y cModel, pero otras columnas (y otras tablas) sólo contienen flujos, no magnitudes.
La siguiente consulta devuelve las coordenadas, las magnitudes cModel en las bandas $g$ y $r$, y convierte los flujos Sérsic a magnitudes AB para recuperarlos.
query = """SELECT coord_ra, coord_dec,
g_cModelMag, g_cModelMagErr,
r_cModelMag, r_cModelMagErr,
scisql_nanojanskyToAbMag(g_sersicFlux) AS g_sersicMag,
scisql_nanojanskyToAbMagSigma(g_sersicFlux, g_sersicFluxErr) AS g_sersicMagErr,
scisql_nanojanskyToAbMag(r_sersicFlux) AS r_sersicMag,
scisql_nanojanskyToAbMagSigma(r_sersicFlux, r_sersicFluxErr) AS r_sersicMagErr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT coord_ra, coord_dec,
g_cModelMag, g_cModelMagErr,
r_cModelMag, r_cModelMagErr,
scisql_nanojanskyToAbMag(g_sersicFlux) AS g_sersicMag,
scisql_nanojanskyToAbMagSigma(g_sersicFlux, g_sersicFluxErr) AS g_sersicMagErr,
scisql_nanojanskyToAbMag(r_sersicFlux) AS r_sersicMag,
scisql_nanojanskyToAbMagSigma(r_sersicFlux, r_sersicFluxErr) AS r_sersicMagErr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
La fase del trabajo es COMPLETED
results
| coord_ra | coord_dec | g_cModelMag | g_cModelMagErr | r_cModelMag | r_cModelMagErr | g_sersicMag | g_sersicMagErr | r_sersicMag | r_sersicMagErr |
|---|---|---|---|---|---|---|---|---|---|
| deg | deg | mag | mag | mag | mag | ||||
| float64 | float64 | float32 | float32 | float32 | float32 | float64 | float64 | float64 | float64 |
| 52.999950842186635 | -28.009791369795494 | 25.3058 | 0.0408128 | 24.8951 | 0.037891 | 25.289549452182214 | 0.040237818711488176 | 24.892949378203916 | 0.03766112794964982 |
| 53.000647668093336 | -28.00041790185584 | 25.0412 | 0.0298784 | 24.4576 | 0.0226485 | 24.866171833290277 | 0.0292662574085082 | 24.292082739141648 | 0.022401841938212753 |
| 52.99865025242912 | -28.007343580438622 | 24.9923 | 0.0309844 | 24.7067 | 0.0317504 | 24.90763455079954 | 0.030462383351975278 | 24.630331766822504 | 0.03144153073250518 |
| 53.00440835952543 | -28.00706527664946 | 25.615 | 0.0891581 | 24.0388 | 0.021853 | 25.824036556658854 | 0.08788197304022516 | 23.975996228411077 | 0.021711488954269238 |
| 52.99728049236805 | -28.004763783217346 | 24.1276 | 0.0187086 | 23.7754 | 0.020053 | 23.905462678258765 | 0.01842487813911017 | 23.66474104374684 | 0.019896250251999065 |
| 52.998611316150786 | -28.007966170045258 | 24.6015 | 0.0201114 | 24.1979 | 0.0186312 | 24.604628401562163 | 0.019900164058944833 | 24.217741365529697 | 0.01851201132941137 |
| 52.99610446568829 | -28.00392847688764 | 25.7216 | 0.0553019 | 24.699 | 0.028772 | 25.51758445383836 | 0.05332594940368145 | 24.509594032041257 | 0.028202493409365273 |
| 52.994574524381925 | -27.997372314676916 | 24.6329 | 0.0226044 | 23.8767 | 0.0155296 | 24.588047465995317 | 0.022427202238376947 | 23.902507096802537 | 0.015430592488508811 |
| 52.998335112826375 | -28.003816346850325 | 24.2705 | 0.0164768 | 24.1018 | 0.0186653 | 24.28554955290755 | 0.016401610324314392 | 24.121507128684378 | 0.018583906770695945 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 53.00766969633569 | -27.993399513118437 | 20.4858 | 0.000620706 | 19.3215 | 0.000333081 | 20.488225674135386 | 0.0005964093735726239 | 19.327588879321173 | 0.000313522792252015 |
| 53.00642044578477 | -27.994667920805927 | 24.3085 | 0.0337899 | 24.1698 | 0.0395691 | 23.392352928047327 | 0.0332268011886009 | 23.19645761026413 | 0.03703635296876196 |
| 52.996802053288405 | -27.9912332351428 | 28.5065 | 0.677682 | 32.7069 | 42.3778 | 28.228616805619353 | 0.7439242460744452 | 34.46578974634167 | 299.92762698447825 |
| 53.0031279692871 | -27.99123590474861 | 29.5039 | 1.75463 | 29.4607 | 3.12418 | 31.701939724362447 | 25.793940395325283 | 31.092177473081613 | 19.884466632324333 |
| 53.003139507715005 | -27.992142682076214 | 29.3874 | 1.50775 | 28.666 | 1.00012 | 27.92504600267281 | 0.6554646047782284 | 27.728928845537737 | 0.7193995074034013 |
| 53.00136705577273 | -27.990401541457896 | 26.7056 | 0.150559 | 26.6686 | 0.180899 | 26.253211444495825 | 0.15207798087462815 | 26.144998117227367 | 0.18148483107217858 |
| 53.001939897066684 | -27.990603538058334 | 25.7765 | 0.07207 | 25.7781 | 0.0942976 | 25.506527466972184 | 0.06893346762410889 | 25.482099994870694 | 0.08844322213745942 |
| 53.00036920322047 | -27.991722047885638 | 27.4609 | 0.267638 | 26.5169 | 0.143943 | 26.846490281567256 | 0.23935535511200468 | 26.0771889088126 | 0.15246200938368937 |
| 53.00070612505027 | -27.99198924376921 | 26.9852 | 0.227693 | 26.5283 | 0.182682 | 26.740069361434774 | 0.244807886464271 | 26.109630148347108 | 0.17823406636097816 |
job.delete()
del query, results
2.4. Obtener nuevas columnas derivadas¶
Recuperar "columnas derivadas" que sean la diferencia entre dos columnas, en este caso, las magnitudes cModel de filtros adyacentes para obtener colores.
query = """SELECT coord_ra, coord_dec,
u_cModelMag - g_cModelMag AS ug_clr,
g_cModelMag - r_cModelMag AS gr_clr,
r_cModelMag - i_cModelMag AS ri_clr,
i_cModelMag - z_cModelMag AS iz_clr,
z_cModelMag - y_cModelMag AS zy_clr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT coord_ra, coord_dec,
u_cModelMag - g_cModelMag AS ug_clr,
g_cModelMag - r_cModelMag AS gr_clr,
r_cModelMag - i_cModelMag AS ri_clr,
i_cModelMag - z_cModelMag AS iz_clr,
z_cModelMag - y_cModelMag AS zy_clr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
len(results)
La fase del trabajo es COMPLETED
141
print(results.colnames)
['coord_ra', 'coord_dec', 'ug_clr', 'gr_clr', 'ri_clr', 'iz_clr', 'zy_clr']
job.delete()
del query, results
3. Restringir valores de columnas¶
3.1. Aplicar operadores relacionales¶
En las consultas anteriores, sólo se utilizó el operador =,
pero otros operadores también están disponibles, por ejemplo: !=, <, >, <= y >=.
Incluir restricciones de consulta en las magnitudes para devolver únicamente objetos que sean más brillantes que la magnitud 25 en todos los filtros.
query = """SELECT coord_ra, coord_dec,
u_cModelMag - g_cModelMag AS ug_clr,
g_cModelMag - r_cModelMag AS gr_clr,
r_cModelMag - i_cModelMag AS ri_clr,
i_cModelMag - z_cModelMag AS iz_clr,
z_cModelMag - y_cModelMag AS zy_clr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND u_cModelMag < 25 AND g_cModelMag < 25
AND r_cModelMag < 25 AND i_cModelMag < 25
AND z_cModelMag < 25 AND y_cModelMag < 25"""
print(query)
SELECT coord_ra, coord_dec,
u_cModelMag - g_cModelMag AS ug_clr,
g_cModelMag - r_cModelMag AS gr_clr,
r_cModelMag - i_cModelMag AS ri_clr,
i_cModelMag - z_cModelMag AS iz_clr,
z_cModelMag - y_cModelMag AS zy_clr
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND u_cModelMag < 25 AND g_cModelMag < 25
AND r_cModelMag < 25 AND i_cModelMag < 25
AND z_cModelMag < 25 AND y_cModelMag < 25
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
La fase del trabajo es COMPLETED
Como ejemplo, imprimir los valores mínimos y máximos de las columnas derivadas.
print(np.min(results['ug_clr']), np.max(results['ug_clr']))
print(np.min(results['gr_clr']), np.max(results['gr_clr']))
print(np.min(results['ri_clr']), np.max(results['ri_clr']))
print(np.min(results['iz_clr']), np.max(results['iz_clr']))
print(np.min(results['zy_clr']), np.max(results['zy_clr']))
-0.22574234008789062 2.437074661254883 0.03248786926269531 1.5774612426757812 -0.13392066955566406 0.775299072265625 -0.0517425537109375 0.5262928009033203 -0.6113967895507812 0.5244102478027344
job.delete()
del query, results
3.2. Aplicar operadores a funciones¶
Sólo se pueden usar los nombres de columnas originales en una restricción.
Por ejemplo, este intento de crear una columna llamada g_sersicMag y luego aplicar también una restricción sobre ella devolverá un error.
SELECT coord_ra, coord_dec,
scisql_nanojanskyToAbMag(g_sersicFlux) AS g_sersicMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND g_sersicMag < 25
La forma correcta de realizar esta consulta es usar el nombre de columna original en la sentencia WHERE.
query = """SELECT coord_ra, coord_dec,
scisql_nanojanskyToAbMag(g_sersicFlux) AS g_sersicMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND scisql_nanojanskyToAbMag(g_sersicFlux) < 25"""
print(query)
SELECT coord_ra, coord_dec,
scisql_nanojanskyToAbMag(g_sersicFlux) AS g_sersicMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND scisql_nanojanskyToAbMag(g_sersicFlux) < 25
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
print(len(results))
La fase del trabajo es COMPLETED 44
job.delete()
del query, results
3.3. Usar WHERE ... BETWEEN ... AND¶
Se puede aplicar una restricción para que el valor de una columna esté entre los valores de otras dos columnas con una sentencia de la forma WHERE a BETWEEN b AND c.
¡El orden importa!
WHERE a BETWEEN b AND cdevolverá todas las filas para las cuales $b < a < c$.WHERE a BETWEEN c AND bdevolverá todas las filas para las cuales $c < a < b$.
Por ejemplo, devolver todos los objetos dentro de la región de búsqueda cónica para los cuales las magnitudes PSF cumplan $g < r < i$. En otras palabras, objetos que sean más brillantes en la banda $g$ que en la $r$, y más brillantes en la banda $r$ que en la $i$ (es decir, objetos azules).
query = """SELECT objectId, g_psfMag, r_psfMag, i_psfMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND r_psfMag BETWEEN g_psfMag AND i_psfMag"""
print(query)
SELECT objectId, g_psfMag, r_psfMag, i_psfMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
AND r_psfMag BETWEEN g_psfMag AND i_psfMag
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
print(len(results))
La fase del trabajo es COMPLETED 3
for i in range(len(results)):
print(results['objectId'][i],
results['g_psfMag'][i],
results['r_psfMag'][i],
results['i_psfMag'][i])
611255141361789816 26.2232 26.2289 26.2984 611255141361790690 26.64 26.7169 27.3359 611255141361791996 28.4808 31.817 33.0504
job.delete()
del query, results
3.4. Usar WHERE ... IN ()¶
La opción de restricción WHERE <col1> IN (valor1, valor2, valor3) es una forma más sencilla de hacer, por ejemplo, WHERE <col1> = valor1 OR <col1> = valor2 OR <col1> = valor3.
Un escenario para usar WHERE ... IN () es cuando la lista de objectId es conocida. Se puede pasar una lista de hasta ~50,000 identificadores.
Definir id_list como una cadena, formateada como una tupla, con los objectId de los tres objetos azules identificados en la sección anterior.
id_array = np.asarray((611255141361789816, 611255141361790690, 611255141361791996),
dtype='long')
id_list = "(" + ", ".join(str(value) for value in id_array) + ")"
print(id_list)
(611255141361789816, 611255141361790690, 611255141361791996)
Crear una consulta para devolver las coordenadas de los tres objetos.
query = """SELECT objectId, coord_ra, coord_dec
FROM dp1.Object
WHERE objectId IN {}""".format(id_list)
print(query)
SELECT objectId, coord_ra, coord_dec
FROM dp1.Object
WHERE objectId IN (611255141361789816, 611255141361790690, 611255141361791996)
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
La fase del trabajo es COMPLETED
Mostrar los resultados.
results
| objectId | coord_ra | coord_dec |
|---|---|---|
| deg | deg | |
| int64 | float64 | float64 |
| 611255141361789816 | 53.005323357996005 | -28.00468291953882 |
| 611255141361790690 | 52.99438633549297 | -27.99473439509563 |
| 611255141361791996 | 52.996802053288405 | -27.9912332351428 |
job.delete()
del query, results
4. Manipular los resultados¶
4.1. Usar con precaución TOP y ORDER BY¶
Advertencia: El servicio TAP primero aplica las restricciones
WHERE, luegoORDER BYy despuésTOP. Si la consulta no está bien acotada, y muchas más filas cumplen las restriccionesWHEREque lasNdevueltas porTOP, entonces todas se ordenan primero, antes de devolver sólo lasNprimeras. Este no es un uso eficiente del servicio TAP compartido.
Se recomienda combinar TOP y ORDER BY sólo si las declaraciones WHERE de la consulta reducen significativamente el número de objetos que tendrían que ser ordenados.
4.2. Limitar filas¶
Se recomienda utilizar regiones espaciales muy pequeñas para restringir el número de filas devueltas, aunque TOP también funcionará.
Para recuperar sólo un subconjunto de las filas que cumplen las restricciones de la consulta, agregar TOP N después de SELECT para devolver únicamente las N filas superiores. Incluir maxrec en la definición del trabajo también funcionará, pero se recomienda usar TOP en lugar de maxrec.
query = """SELECT TOP 10 coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1"""
print(query)
SELECT TOP 10 coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1
Ejecutar la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
Recuperar los resultados y confirmar que sólo se devuelven 10 filas.
assert job.phase == 'COMPLETED'
results = job.fetch_result()
assert len(results) == 10
print(len(results))
10
Limpieza.
job.delete()
del query, results
4.3. Ordenar la tabla¶
4.3.1. Ordenar con astropy¶
Recuperar los resultados de la consulta como una tabla de astropy y usar el método sort.
Crear una consulta similar a la de la Sección 4.1, pero sin usar TOP y que sólo devuelva filas con g_cModelMag más brillante que magnitud 20.
query = """SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1
AND g_cModelMag < 20"""
print(query)
SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1
AND g_cModelMag < 20
Enviar el trabajo de la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
Recuperar los resultados como una tabla formateada en astropy usando to_table(), para poder usar el método sort.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
Ordenar la tabla de astropy por g_cModelMag en orden descendente (es decir, usar reverse=True; el valor por defecto es False, para orden ascendente).
También es posible ordenar por múltiples columnas, por ejemplo: results.sort(['columna_1', 'columna_2']).
results.sort('g_cModelMag', reverse=True)
Mostrar los resultados, ahora ordenados por magnitud en banda $g$, con el objeto más débil en la primera fila.
results
| coord_ra | coord_dec | g_cModelMag |
|---|---|---|
| deg | deg | mag |
| float64 | float64 | float32 |
| 52.917598505724484 | -28.036759972159413 | 19.9929 |
| 53.04775482029748 | -27.975392984903166 | 19.9504 |
| 53.03584306939495 | -27.928161395037968 | 19.9287 |
| 53.03903906240283 | -27.959458794774264 | 19.9 |
| 52.96663897778455 | -27.963653398451722 | 19.874 |
| 53.00918641402325 | -28.044180804131248 | 19.7971 |
| 53.01829138799236 | -28.075509632285595 | 19.7953 |
| 53.07382332409231 | -28.06505463389963 | 19.752 |
| 53.09918248237757 | -27.979397996279193 | 19.6067 |
| ... | ... | ... |
| 52.91466707323275 | -28.027825200964536 | 17.1495 |
| 52.97177339646181 | -28.049185382350746 | 17.018 |
| 53.01835078638047 | -28.085549256632248 | 17.0006 |
| 53.069949903324094 | -28.039568580067808 | 16.9427 |
| 53.09326022159075 | -28.018392693608014 | 16.6915 |
| 53.08453522823213 | -28.026264129464558 | 16.2093 |
| 52.92140884571618 | -28.052060061799228 | 16.1101 |
| 52.956019116141974 | -27.952755305471864 | 15.8976 |
| 52.92022761953359 | -28.010189784283277 | 15.6904 |
Limpieza.
job.delete()
del query, results
4.3.2. Ordenar con ORDER BY¶
Agregar una cláusula ORDER BY a la consulta TAP para ordenar los resultados en orden ascendente (ASC) o descendente (DESC).
Advertencia: Agregar cláusulas
ORDER BYa las consultas TAP requiere más procesamiento que las consultas sin ordenar y consume más del recurso compartido que es el servicio TAP. Por esta razón, se recomienda ordenar usandoastropy(Sección 4.3.1).
Ordenar los resultados por valores de g_cModelMag en orden descendente.
query = """SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1
AND g_cModelMag < 20
ORDER BY g_cModelMag DESC"""
print(query)
SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.1)) = 1
AND g_cModelMag < 20
ORDER BY g_cModelMag DESC
Enviar el trabajo de la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
Devolver los resultados.
assert job.phase == 'COMPLETED'
results = job.fetch_result()
Mostrar los resultados, que ya están ordenados por la magnitud en banda $g$ de más débil a más brillante.
results
<DALResultsTable length=51>
coord_ra coord_dec g_cModelMag
deg deg mag
float64 float64 float32
------------------ ------------------- -----------
52.917598505724484 -28.036759972159413 19.9929
53.04775482029748 -27.975392984903166 19.9504
53.03584306939495 -27.928161395037968 19.9287
53.03903906240283 -27.959458794774264 19.9
52.96663897778455 -27.963653398451722 19.874
53.00918641402325 -28.044180804131248 19.7971
53.01829138799236 -28.075509632285595 19.7953
53.07382332409231 -28.06505463389963 19.752
53.09918248237757 -27.979397996279193 19.6067
... ... ...
52.91466707323275 -28.027825200964536 17.1495
52.97177339646181 -28.049185382350746 17.018
53.01835078638047 -28.085549256632248 17.0006
53.069949903324094 -28.039568580067808 16.9427
53.09326022159075 -28.018392693608014 16.6915
53.08453522823213 -28.026264129464558 16.2093
52.92140884571618 -28.052060061799228 16.1101
52.956019116141974 -27.952755305471864 15.8976
52.92022761953359 -28.010189784283277 15.6904
Limpieza.
job.delete()
del query, results
5. Filas de agregación¶
Las funciones de agregación de SQL y ADQL son: COUNT, SUM, AVG, MIN y MAX.
Se utilizan para devolver estadísticas de los valores de una columna en una consulta, en lugar de los valores en sí.
Definir una consulta para devolver el número (COUNT) de imágenes en banda $r$ obtenidas para el campo ECDFS, y también la Fecha Juliana Modificada (MJD) de la primera (MIN) y última (MAX) imagen.
query = """SELECT COUNT(expMidptMJD) AS n_visits,
MIN(expMidptMJD) AS min_mjd, MAX(expMidptMJD) AS max_mjd
FROM dp1.Visit
WHERE CONTAINS(POINT('ICRS', ra, dec),
CIRCLE('ICRS', 53.13, -28.10, 3)) = 1
AND band = 'r'"""
print(query)
SELECT COUNT(expMidptMJD) AS n_visits,
MIN(expMidptMJD) AS min_mjd, MAX(expMidptMJD) AS max_mjd
FROM dp1.Visit
WHERE CONTAINS(POINT('ICRS', ra, dec),
CIRCLE('ICRS', 53.13, -28.10, 3)) = 1
AND band = 'r'
Enviar el trabajo de la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
Devolver los resultados.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
Mostrar los resultados.
results
| n_visits | min_mjd | max_mjd |
|---|---|---|
| int64 | float64 | float64 |
| 237 | 60623.25932903928 | 60655.24643617473 |
Limpieza.
job.delete()
del query, results
5.1. Usar GROUP BY¶
Para aplicar las funciones de agregación de ADQL / SQL a grupos de filas en lugar de a toda la tabla, usar GROUP BY.
Definir una consulta para devolver el visit, la MJD, la band y el número de fuentes detectadas por visita, uniendo las tablas Visit y Source, y usando GROUP BY sobre visit. Restringir la consulta a imágenes en banda $r$ obtenidas dentro de un intervalo de $\sim30$ minutos entre MJD 60623.250 y 60623.270.
query = """SELECT v.visit, v.expMidptMJD, v.band,
COUNT(s.sourceId) AS n_sources
FROM dp1.Visit AS v
JOIN dp1.Source AS s ON s.visit = v.visit
WHERE CONTAINS(POINT('ICRS', v.ra, v.dec),
CIRCLE('ICRS', 53.13, -28.10, 3)) = 1
AND v.band = 'r'
AND v.expMidptMJD > 60623.250
AND v.expMidptMJD < 60623.270
GROUP BY v.visit"""
print(query)
SELECT v.visit, v.expMidptMJD, v.band,
COUNT(s.sourceId) AS n_sources
FROM dp1.Visit AS v
JOIN dp1.Source AS s ON s.visit = v.visit
WHERE CONTAINS(POINT('ICRS', v.ra, v.dec),
CIRCLE('ICRS', 53.13, -28.10, 3)) = 1
AND v.band = 'r'
AND v.expMidptMJD > 60623.250
AND v.expMidptMJD < 60623.270
GROUP BY v.visit
Enviar el trabajo de la consulta.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
Recuperar los resultados.
assert job.phase == 'COMPLETED'
results = job.fetch_result().to_table()
Mostrar los resultados.
results
| visit | expMidptMJD | band | n_sources |
|---|---|---|---|
| d | |||
| int64 | float64 | object | int64 |
| 2024110800246 | 60623.25932903928 | r | 27708 |
| 2024110800247 | 60623.25989537033 | r | 27446 |
| 2024110800250 | 60623.262127748836 | r | 27834 |
| 2024110800251 | 60623.2626942534 | r | 27474 |
| 2024110800254 | 60623.2648977835 | r | 28241 |
| 2024110800255 | 60623.265465752265 | r | 27057 |
| 2024110800258 | 60623.2676935763 | r | 26917 |
| 2024110800259 | 60623.268262389945 | r | 27709 |
Limpieza.
job.delete()
del query, results