Autor: Eduardo Martín Calleja
En esta entrada vamos a ver un método muy sencillo de ejecutar sentencias SQL sobre el servidor del Sloan Digital Sky Survey (SDSS). De esta manera podremos obtener una gran cantidad de datos acerca de todo tipo de objetos celestes.
Este post está escrito íntegramente utilizando el Notebook de IPython. También se utilizará el módulo mechanize de Python para navegar por la web y ejecutar de forma interactiva formularios HTML. Iré explicando en detalle cada uno de los pasos, y al final haré un resumen para evitar que nos perdamos en los detalles y mostrar la facilidad de utilización del método utilizado.
Importaciones y referencias¶
Para una introducción a la ejecución de peticiones SQL sobre el SDSS no se me ocurre mejor recurso que su propio tutorial, junto con su complemento de ejemplos: Sample SQL Queries
Para ver que tablas y vistas existen en la base de datos, y qué información hay disponible en cada una de ellas, una herramienta imprescindible será: Schema Browser
Y, para ejecutar de forma interactiva un SQL contra la base de datos del SDSS, accedase a la página: SQL Search
%matplotlib inline
from __future__ import division
import numpy as np
import pandas as pd
import mechanize
from StringIO import StringIO # Para leer un string como si fuera un fichero
# Generar un cuadro con versiones de las librerías utilizadas en este notebook
#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information numpy, pandas, StringIO
# URL de la página de búsquedas de la base de datos DR10
url = "http://skyserver.sdss3.org/dr10/en/tools/search/sql.aspx"
Preparación del SQL¶
Antes de comenzar a interactuar desde Python con la página web del SDSS que nos permite enviar una sentencia SQL a su base de datos, vamos a preparar un SQL de prueba en una variable de tipo string. En este SQL buscaremos 10 objetos (¡se trata de una prueba!) de tipo 6 = 'STAR', con fotometría límpia y color azul, en una región del cielo determinada. Eso si, debemos omitir las líneas con comentarios en el SQL (aquellas precedidas de doble guión --) al crear el fichero.
Nota: En una próxima entrada en este blog, se verá cuales son las tablas (o vistas) y campos más útiles para construir nuestras SELECT.
# Como el string a generar ocupa más de una línea
#Utilizamos paréntesis para concatenar automáticamente las líneas
s = ('SELECT TOP 10 '
'objID, ra, dec, modelMag_u, modelMag_g '
'FROM '
'PhotoPrimary '
'WHERE '
'ra BETWEEN 140 and 141 '
'AND dec BETWEEN 20 and 21 '
'AND type = 6 '
'AND clean = 1 '
'AND modelMag_u - modelMag_g < 0.5')
# Comprobación:
s
Navegación con el módulo mechanize¶
El primer paso para utilizar mechanize será crear un objeto tipo Browser para poder hacer la navegación utilizando sus métodos
br = mechanize.Browser()
A continuación, debemos abrir una sesión con el url que apunta a la página web del SDSS que nos permite hacer las búsquedas SQL:
resp = br.open(url)
resp.info()
Cuando se desea interactuar con una página web, estaremos interesados en conocer los formularios HTML que contiene. Un formulario HTML es una sección del documento comprendida entre las etiquetas:
<FORM> y </FORM>
Un formulario contiene una serie de objetos especiales denominados controles, tales como checkboxes, radio buttons, menus, etc. y labels de estos objetos. El usuario interactua con la página modificando un control, por ejemplo seleccionando una opción, introduciendo un texto en un campo, etc. y haciendo un envío de dicho form al servidor.
Cada form en la página tiene un nombre, si bien este puede en algunos casos estar vacío. Para listar estos nombres de los formularios existentes en la página podemos escribir:
for f in br.forms():
print f.name
Es decir, en este caso hay un único form en la página, de nombre "sql"
A su vez, cada formulario posee una lista de controles, que tambien poseen un nombre, el cual también puede estar en blanco. Para listar los formularios en la página, junto con sus controles y tipo de cada control, podemos hacer lo siguiente:
for f in br.forms():
print f.name
for c in f.controls:
print '\t',c.name, '\t', c.type
Centraremos nuestra atención en el control "cmd" que es un control de texto en el cual debemos escribir nuestro SQL, y el control "format" que, tal como se puede ver en la página web en el navegador, permite controlar el tipo de salida deseada: HTML, XML, CSV, etc. Para poder acceder a estos controles debemos seleccionar previamente el formulario al cual pertenecen:
br.select_form(name="sql")
A continuación, modificaremos el control 'cmd' para introducir nuestro SQL, y el control 'format', para seleccionar la salida en formato csv.
br['cmd'] = s # El string con el sql
br['format']=['csv'] # formato de salida de los datos
response = br.submit()
El contenido del fichero csv con la respuesta del sql podemos obtenerlo como un string con el método get_data()
print response.get_data()
Pero, ¡atención!, el método submit() cierra la sesión, por lo que, para enviar otro SQL habrá que repetir el br.open() y el br.select()
A continuación, y con el fin de poder tratar los datos con más facilidad, lo más aconsejable es generar un dataframe de Pandas. Observemos que la primera línea debe ser descartada, y la segunda fila contiene los nombres de las columnas, por lo que la mantendremos en el dataframe
file_like = StringIO(response.get_data())
df =pd.read_csv(file_like, skiprows = 1) # saltamos la primera línea
df
A partir de aquí podríamos renombrar las columnas dandoles un nombre más a nuestro gusto, y calcular una nueva columna como diferencia de las columnas u y g, la cual nos indicará el color del astro.
df.columns = ['objID','ra','dec','u','g']
df['u-g'] = df['u']-df['g']
df
Resumen¶
Una vez visto el fundamento de la utilización del módulo mechanize y la creación de un dataframe de Pandas, podemos definir una función para agilizar el proceso de nuevos SQL
def SDSS_select(sql):
'''input: string con una sentencia SQL válida
output: un dataframe de Pandas
'''
br.open(url)
br.select_form(name="sql")
br['cmd'] = sql
br['format']=['csv']
response = br.submit()
file_like = StringIO(response.get_data())
return pd.read_csv(file_like, skiprows=1)
Los pasos a seguir serán los siguientes:
- Las instrucciones siguientes se ejecutarán solo la primera vez:
# URL de la página de búsquedas de la base de datos DR10
url = "http://skyserver.sdss3.org/dr10/en/tools/search/sql.aspx"
- Preparamos un string con nuestro SQL
sql = ('SELECT TOP 10 '
'objID, ra, dec, modelMag_u, modelMag_g, modelMag_r, modelMag_i, modelMag_z '
'FROM Star '
'WHERE ra BETWEEN 150 and 152 AND dec BETWEEN 30 and 31 AND clean = 1')
- Llamamos a la función, obteniendo un dataframe de Pandas como retorno
df = SDSS_select(sql)
Y ya tenemos listo nuestro dataframe
df
Aquí finalizo este post, pero el método de acceso a la base de datos del SDSS que hemos visto aquí lo utilizaré en futuras entradas para analizar, en base a datos reales, diversas propiedades de los objetos celestes.
No hay comentarios:
Publicar un comentario