Blog de Carlos González

Estudiante de la Universidad de Valencia

Lectura y manejo de datos astronómicos

Posted by Carlos on 4 febrero, 2019

Repositorios (I): CALTECH

Muchas instituciones ofrecen al público multitud de datos sin procesar (RAW) o ya procesados de sus centros astronómicos, con el objetivo de divulgar los descubrimientos y fomentar la investigación. En el caso particular de las misiones Kepler y K2, el Instituto Tecnológico de California ha creado el portal NASA Exoplanet Archive donde se pueden obtener diferentes tipos de archivos y tablas sobre los objetos celestes estudiados.

Para poder acceder a las tablas de datos, seleccionamos la opción KOI (All Lists) del menú Data (https://exoplanetarchive.ipac.caltech.edu/cgi-bin/TblView/nph-tblView?app=ExoTbls&config=koi). Una vez dentro de la herramienta Kepler Objects of Interest, encontramos diferentes tablas que coleccionan datos. Si, por ejemplo, deseamos descargar las 10 primeras entradas (filas) de la colección Q1-Q17 DR24, seleccionaremos la pestaña de esta colección y las filas escogidas, y pulsaremos alguna de las opciones del menú Download Data Products.

En lugar de descargar directamente los datos, el portal nos ofrecerá descargar un archivo .bat (archivo de procesamiento por lotes) con las órdenes para obtener los datos de un repositorio de Internet desde la consola de comandos de nuestro equipo. Dependiendo de las características del ordenador, deberemos modificar algunas características del fichero, así como instalar componentes adicionales.

En el caso de utilizar un sistema operativo Windows, se deberá instalar la utilidad GNU Wget (http://gnuwin32.sourceforge.net/packages/wget.htm) y añadir el directorio a las variables de entorno (PATH) de Windows; además, se deberá añadir al nombre del ejecutable la versión (p. ej. /GnuWin32/bin/wget-1.11.4.exe), y modificar el fichero .bat para que las órdenes se ejecuten bajo ese nombre de ejecutable (wget-1.11.4), en lugar del establecido por defecto (wget). Otro problema común es la aparición de comillas simples en el fichero .bat, que deberán ser reemplazadas por comillas dobles para que el programa se ejecute correctamente. Para evitar complicaciones que surgan por conexiones seguras, deberá insertarse en cada orden el comando --no-check-certificate.

Manejo de archivos FITS

Los archivos .fits (Flexible Image Transport System) son los que habitualmente se utilizan en astronomía para el intercambio de información, tanto de tipo gráfico como documental. Además de albergar imágenes de gran resolución, permiten almacenar tablas con encabezados que pueden ser utilizadas para multitud de aplicaciones.

Las curvas de luz que se pueden obtener en el portal anterior, correspondientes a las misiones Kepler y K2, se encontrarán en este formato una vez descargadas. Para poder abrirlas en Python, debemos recurrir a la librería astropy. A continuación, se muestra un ejemplo que permite leer los ficheros .fits de la carpeta situada en el directorio raíz del módulo:

from astropy.visualization import astropy_mpl_style
from astropy.utils.data import get_pkg_data_filename
import matplotlib.pyplot as plt
from astropy.io import fits
from os import walk


def plot_images(path):
    # Identify all data files
    file = []
    for dir_path, dir_names, file_names in walk("C:/Users/Carlos/PycharmProjects/TFG/test/" + path):
        file.extend(file_names)
        break

    # Set figure parameters
    columns = int(len(file)/1)
    if len(file) > 0:
        if columns < 1:
            columns = 1
        elif columns > len(file):
            columns = len(file)
    rows = len(file) // columns
    if len(file) / columns > rows:
        rows = rows + 1

    plt.style.use(astropy_mpl_style)
    plt.figure()

    # get images
    for i in range(0, len(file)):
        try:
            image_file = get_pkg_data_filename(path + file[i])
            fits.info(image_file)
            image_data = fits.getdata(image_file, ext=2)
            plt.subplot(rows, columns, i+1)
            plt.imshow(image_data)
            plt.colorbar()
        except TypeError:
            pass

    # show
    plt.show()

plot_images("fits/")

Repositorios (II): MAST

También desde el repositorio del MAST —siglas de Multimission Archive at Space Telescope Science Institute (STScI), posteriormente renombrado como Barbara Ann Mikulski Archive for Space Telescopes, en honor a la senadora de los EE. UU.— podemos acceder a la información de la misión Kepler, bien manualmente, bien haciendo uso de un módulo que extiende a la librería astropy, llamado astroquery. A través de este módulo, podemos lanzar consultas automáticas al menos a 19 repositorios distintos (incluido el de la NASA), tal y como se puede ver en el siguiente ejemplo, desarrollado a partir del tutorial en línea del STScI:

from astroquery.mast import Observations
import matplotlib.pyplot as plt
from astropy.table import Table
from astropy.io import fits


sel = {"primary": 0, "light": 1, "aperture": 2}


def data_get(collection="Kepler", target="kplr011446443", product="kplr011446443-2009131110544_slc.fits"):
    observations = Observations.query_criteria(target_name=target, obs_collection=collection)
    all_prod = Observations.get_product_list(observations[1])
    my_prod = Observations.filter_products(all_prod, productFilename=product, extension="fits", mrp_only=False)
    Observations.download_products(my_prod, mrp_only=False, cache=False)


def data_read(product="kplr011446443-2009131110544_slc.fits"):
    filename = "./mastDownload/Kepler/kplr011446443_sc_Q113313330333033302/" + product

    with fits.open(filename) as hdulist:
        header1 = hdulist[sel["light"]].header
    print(repr(header1[0:24]))  # repr() prints the info into neat columns

    with fits.open(filename) as hdulist:
        binaryext = hdulist[sel["light"]].data

    binarytable = Table(binaryext)
    print(binarytable[1:5])

    return filename


def data_plot_light(filename):
    with fits.open(filename, mode="readonly") as hdulist:
        # Read in the "BJDREF" which is the time offset of the time array.
        bjdrefi = hdulist[sel["light"]].header['BJDREFI']
        bjdreff = hdulist[sel["light"]].header['BJDREFF']

        # Read in the columns of data.
        times = hdulist[sel["light"]].data['time']
        sap_fluxes = hdulist[sel["light"]].data['SAP_FLUX']
        pdcsap_fluxes = hdulist[sel["light"]].data['PDCSAP_FLUX']

    # Convert the time array to full BJD by adding the offset back in.
    bjds = times + bjdrefi + bjdreff

    plt.figure(figsize=(9, 4))

    # Plot the time, uncorrected and corrected fluxes.
    plt.plot(bjds, sap_fluxes, '-k', label='SAP Flux')
    plt.plot(bjds, pdcsap_fluxes, '-b', label='PDCSAP Flux')

    plt.title('Kepler Light Curve')
    plt.legend()
    plt.xlabel('Time (days)')
    plt.ylabel('Flux (electrons/second)')
    plt.show()


def data_plot_aperture(filename):
    with fits.open(filename) as hdulist:
        imgdata = hdulist[sel["aperture"]].data

    print(imgdata)

    plt.figure(2)
    plt.title('Kepler Aperture')
    plt.imshow(imgdata)
    plt.xlabel('Column')
    plt.ylabel('Row')
    plt.colorbar()
    plt.show()


data_get()
file = data_read()
data_plot_light(file)
Curva de luz. Imagen de apertura.

Manipulación de las curvas de luz

La información que deseamos extraer consiste en cada uno de los posibles cruces de un exoplaneta en la trayectoria entre su eje de traslación (sol) y el observador (telescopio). Para ello, escogemos los datos de luminosidad corregidos, presentes en la columna PDCSAP flux, donde se han eliminado artificios producidos por el telescopio y, tomando como ejemplo el proceso de selección escogido por C. J. Shalluey y A. Vanderburg, normalizaremos la gráfica en torno a los valores [-1, 0], y la dividiremos en periodos de 200 unidades alrededor de los mínimos que localicemos (en nuestro caso, se han tomado los valores de la curva normalizada menores a -0,8 para seleccionar los mínimos). El código implementado como ejemplo es el siguiente:

from astroquery.mast import Observations
import matplotlib.pyplot as plt
from astropy.io import fits
import numpy as np
import os


sel = {"primary": 0, "light": 1, "aperture": 2}


def data_get(collection="Kepler", target="kplr011446443", product="kplr011446443-2009131110544_slc.fits"):
    if not os.path.isfile("./mastDownload/Kepler/kplr011446443_sc_Q113313330333033302/" + product):
        observations = Observations.query_criteria(target_name=target, obs_collection=collection)
        all_prod = Observations.get_product_list(observations[1])
        my_prod = Observations.filter_products(all_prod, productFilename=product, extension="fits", mrp_only=False)
        Observations.download_products(my_prod, mrp_only=False, cache=False)


def data_plot_light(file="./mastDownload/Kepler/kplr011446443_sc_Q113313330333033302/",
                    product="kplr011446443-2009131110544_slc.fits"):
    filename = file + product
    with fits.open(filename, mode="readonly") as hdulist:
        # Read in the "BJDREF" which is the time offset of the time array.
        bjdrefi = hdulist[sel["light"]].header['BJDREFI']
        bjdreff = hdulist[sel["light"]].header['BJDREFF']

        # Read in the columns of data.
        times = hdulist[sel["light"]].data['time']
        # sap_fluxes = hdulist[sel["light"]].data['SAP_FLUX']
        pdcsap_fluxes = hdulist[sel["light"]].data['PDCSAP_FLUX']

    # Convert the time array to full BJD by adding the offset back in.
    bjds = times + bjdrefi + bjdreff

    arr = norm_data(pdcsap_fluxes)

    global_min = []
    local_min = []

    for i in arr:
        if float(i) > -0.8:
            if len(local_min) > 0:
                global_min.append(np.min(local_min))
                local_min = []

        if float(i) < -0.8:
            local_min.append(i)

    plt.figure(figsize=(9, 4))
    ini = 1

    for j in global_min:
        central = np.where(arr == j)[0][0]
        plt.subplot(2, 2, ini)
        plot_data(bjds[central-100:central+100], arr[central-100:central+100])
        ini += 1

    plt.show()


def plot_data(axis_x, axis_y):
    plt.plot(axis_x, axis_y, '-b', label='PDCSAP Flux')
    plt.title('Kepler Light Curve')
    plt.legend()
    plt.xlabel('Time (days)')
    plt.ylabel('Flux (electrons/second)')


def norm_data(data):
    array = np.array(data)
    arr_max = np.nanmax(array)
    for i in range(0, len(array)):
        array[i] = array[i] - arr_max
    arr_min = np.nanmin(array)
    for i in range(0, len(array)):
        array[i] = array[i] / abs(arr_min)
    return array


col = "Kepler"
tar = "kplr011446443"
pro = "kplr011446443-2009131110544_slc.fits"

data_get(col, tar, pro)
data_plot_light(product=pro)
Curvas de luz normalizadas con respecto al eje Y (valores de -1 a 0), obtenidas a través de la selección de los valores mínimos de la gráfica original.

Posted in Exoplanetas, Misiones, Python | No Comments »

Desarrollo de interfaces gráficas en Python

Posted by Carlos on 28 enero, 2019

Aunque el principal potencial de Python se encuentra en el trabajo de procesamiento de datos, a través del entramado de librerías que permite manejar, también es posible dotar a nuestros programas de un entorno amigable y controlado, que establezca límites en las opciones del usuario y le brinde una manejabilidad superior al entorno de consola.

Por defecto, la instalación de Python para Windows incorpora la librería Tkinter, que no es sino una variante de la biblioteca gráfica de propósito general Tcl/Tk, y que permite la creación de formularios con multitud de elementos para el manejo de la información (botones, listas, menús...). Aunque existen otras bibliotecas gráficas con mucho potencial, como Pyforms o PyQt, es preferible utilizar Tkinter por encontrarse ampliamente documentado (se considera un estándar) y por tener una rápida curva de aprendizaje.

También existen programas que facilitan la creación de formularios con Tkinter, como es el caso de PAGE (Python Automatic GUI Generator) que, además de proveer un entorno de diseño WYSIWYG, permite separar en módulos diferentes la vista gráfica de los servicios que invoca. Para ejecutar PAGE es necesario tener instalada una distribución de Tcl/Tk, por ejemplo ActiveTcl.

Ejemplo de programa con GUI

Siguiendo el ejemplo anterior sobre un lector de imágenes, desarrollamos dos ventanas gráficas con Tkinter que se corresponderán con el formulario principal, y una ventana de acción con una lista. Otras ventanas, como el diálogo de selección de directorio, o los mensajes y alertas, se invocarán mediante procedimientos específicos de Tkinter.

Código del programa

Descargar aquí (PDF)

Aspecto de las ventanas

 

Posted in Python | No Comments »

Ejemplo en Python: lector de imágenes

Posted by Carlos on 28 diciembre, 2018

Para introducirnos en Python, hemos desarrollado un programa de ejemplo que permite leer ficheros de entrada (en nuestro caso, imágenes PNG), y obtener información sobre él a través de un filtro sencillo.

El programa deberá leer los datos depositados en una carpeta determinada, y procederá a listar los ficheros. Posteriormente, los interpretará como imágenes que, para este ejemplo, serán fotografías tomadas del centro de la Vía Láctea (recabadas en la web del ESA Hubble Science Archive) (Imagen 1). Fusionando todas las imágenes, elaborará una nueva imagen con valores promediados (Imagen 2). Por último, realizará un filtrado por luminosidad (Imagen 3)

Código del programa

Descargar aquí (PDF)

Resultados

Imagen 1. Colección de imágenes del centro de la Vía Láctea. Imagen 2. Fusión con luminosidad promedio de la colección. Imagen 3. Filtro de contraste: RGB promedio al 50%.

Posted in Python | No Comments »

Técnicas de aprendizaje automático

Posted by Carlos on 27 diciembre, 2018

Se pueden distinguir en dos grandes categorías:

Aprendizaje supervisado

Consiste en ofrecer al sistema “datos de entrenamiento” que le permitan deducir la función a implementar. Generalmente, los datos se introducen como entradas y salidas, siendo estos últimos los resultados que se esperan de la operación. Los métodos de aprendizaje supervisado se agrupan en:

  • Clasificación: se busca identificar a qué conjunto de categorías, previamente establecidas, pertenece una nueva observación.
  • Regresión: se pretende estimar la relación entre los datos entregados, de forma que se puede prever su evolución (cómo cambia la variable dependiente en función de la independiente).

Aprendizaje no supervisado

No necesita tener “datos de entrenamiento” a priori, ya que se toman los valores de entrada como variables aleatorias, construyéndose un modelo de densidad para el conjunto de datos. De este tipo encontramos:

  • Agrupamiento (clustering): se agrupan conjuntos de datos tomados de la entrada según su similitud. Se utiliza en los procesos de segmentación de imágenes digitales, donde cada pixel recibe unas propiedades que lo asemejan o distancian de otros, formándose agrupaciones de datos estadísticamente similares.

Posted in Conceptos básicos | No Comments »