Euclid data on ESA Datalabs#

This walkthrough finds every SIR exposure of a galaxy, stacks its spectrum, and builds an Hα line map. It runs on ESA Datalabs, where the Euclid data products and the SIR calibration files are mounted on the file system.

The example target is a galaxy at z = 0.751 in the COSMOS field.

import numpy as np
from matplotlib import pyplot as plt

import gelsa
from gelsa import analysis, visu
from gelsa.esa.euclid_archive import EuclidArchive

ra, dec, redshift = 150.09382, 2.503955, 0.751

Connect to the archive#

The archive is queried with astroquery. EuclidArchive wraps a logged-in connection with queries for the products gelsa needs:

from astroquery.esa.euclid.core import EuclidClass

Euclid = EuclidClass()
Euclid.login(credentials_file="password")   # a file with your username and password
archive = EuclidArchive(Euclid)

Query results are cached on disk in ~/.cache/gelsa, so running a query again costs nothing. Set GELSA_CACHE_DIR to use a different location.

On Datalabs, the calibration files are found automatically:

G = gelsa.Gelsa()

Direct image and line map grid#

Load a MER image stamp around the target. Its WCS also sets the grid of the line map:

stamp, wcs = archive.load_stamp(ra, dec, filter="NIR_H", survey="cosmos",
                                width=101, height=101)
wcs.array_shape = stamp.shape

plt.subplot(projection=wcs)
plt.imshow(visu.normalize_image(stamp, levels=(1, 99.9)), cmap="binary_r")

Find the SIR exposures#

query_sir_frames() returns the paths of the SIR science frames near a position, one for each pointing. To keep one grism only, filter the paths by name:

paths = archive.query_sir_frames(ra, dec, radius_deg=0.5)
paths = [p for p in paths if "BGS" in p]    # blue grism only

Stack the spectrum#

Give the frame list to Analysis, cut out the target in each exposure, and stack:

A = analysis.Analysis(G)
A.read_file_list(paths)
A.crop(ra, dec, redshift=redshift, padx=50, pady=50)

spec = A.build_stacked_2D_spectrum(wave_range=(9200, 13700))

plt.plot(spec["wavelength"], spec["spec1d"])
plt.xlabel("Wavelength (Å)")
plt.ylabel("Flux (erg s$^{-1}$ cm$^{-2}$ Å$^{-1}$)")

Exposures in which the target does not fall on a detector are skipped.

Continuum subtraction#

To isolate emission lines, subtract a median filtered continuum from each cutout before stacking:

from gelsa import continuum_subtraction as csb

cs = csb.MedianFilterCutout(median_filter_size_pix=50)
A.crop(ra, dec, redshift=redshift, padx=50, pady=50,
       continuum_subtraction=cs)

Emission line map#

Resample the light at the observed Hα wavelength onto the stamp’s WCS:

line_map, line_var, norm, count = A.build_stacked_line_map(
    6564.61 * (1 + redshift), wcs)

plt.subplot(projection=wcs)
plt.imshow(visu.normalize_image(line_map, levels=(1, 99)))

Interactive line map studio#

In a Jupyter notebook on Datalabs, LineMapStudio runs this whole pipeline from widgets: log in, choose a target, stack, adjust the colours, and export publication-quality figures.

from gelsa.esa import line_map_studio

studio = line_map_studio.make_line_map_studio()
studio