Reading-in Data¶
MOSViz will be able to read in NIRSpec MSA data straight from the pipeline or archive. This will include 1D and 2D spectra, images, data tables, and associated images. This page documents how to read in MOS data from another observatory. An example is shown at the bottom (Defining custom readers for spectra and cutouts).
The general workflow can be summarized as follows:
- Start Glue by typing
glue
in the command line - In Glue, click on the folder icon and open the file containing the Data Table for your data set.
- Drag the file from the Data Collection window into the main canvas.
- Select ‘MOSViz Viewer’ from the pop-up menu.
- Use the green arrow buttons at the top of the viewer to switch between objects.
Overview¶
MOSViz requires at minimum the following input:
- A catalog of targets in tabular form
- A 1D and 2D spectrum for each target
- A cutout image for each target
The main data file that will be read in and used by the MOSViz viewer is the catalog. The catalog can be in any format that Glue understands (such as a FITS table, VO table, ASCII table, and so on). The main constraint is that the table should include columns with the following information for each target:
Column | Default name | Units |
---|---|---|
File path to the 1D spectrum | spectrum1d |
|
File path to the 2D spectrum | spectrum2d |
|
File path to the image cutout | cutout |
|
Right ascension of the slit center (FK5 J2000) | ra |
degrees |
Declination of the slit center (FK5 J2000) | dec |
degrees |
Width of the slit | slit_width |
arcseconds |
Length of the slit | slit_length |
arcseconds |
The columns can have any name, but if they are given the name in the Default name column above, they will be automatically recognized. In addition, the catalog can contain any other useful information such as source names, magnitudes, stellar masses, star-formation rates, etc. These are not required, but including them will allow selections to be done on those parameters.
When adding a dataset to the MOSViz viewer for the first time in glue, the following dialog will appear:
This dialog asks to confirm the column names and also asks to select the appropriate readers for the 1D and 2D spectra as well as the cutouts. In Defining custom readers for spectra and cutouts we show how to define custom readers for spectra and cutouts in case there isn’t an appropriate built-in reader available, and in Writing the Data Table we show how to tell MOSViz which readers/columns to use by default.
Defining custom readers for spectra and cutouts¶
This example uses spectra and cutout images of galaxies at 0.2<z<1.2 which have spectra from the DEIMOS multi-object spectrograph on Keck and color cut-out images already created from Hubble/ACS. These galaxies are from the DEEP2 Survey. The spectra can be obtained from the DEEP2 Data Release page.
MOSViz is a Glue plugin so we’ll write our own Custom Data Loaders
to read data. All we need to do is write a function which takes a filename as
input and returns a glue Data
object. For this example, we have three
different types of data: a 1D Spectrum, a 2D spectrum, and a cutout image.
1D Spectrum Reader¶
MOSViz expects the 1D Spectrum Data object to have three components: Wavelength, Flux, and Uncertainty. The final reader we are going to write is as follows:
from astropy.io import fits
from glue.core import Data
from mosviz.loaders.mos_loaders import mosviz_spectrum1d_loader
@mosviz_spectrum1d_loader('DEIMOS 1D Spectrum')
def deimos_spectrum1D_reader(filename):
"""
Data loader for Keck/DEIMOS 1D spectra.
This loads the 'Bxspf-B' (extension 1) and 'Bxspf-R' (extension 2) and
appends them together to proudce the combined Red/Blue Spectrum along
with their Wavelength and Inverse Variance arrays.
"""
hdulist = fits.open(filename)
data = Data(label='1D Spectrum')
data.header = hdulist[1].header
full_wl = np.append(hdulist[1].data['LAMBDA'][0], hdulist[2].data['LAMBDA'][0])
full_spec = np.append(hdulist[1].data['SPEC'][0], hdulist[2].data['SPEC'][0])
full_ivar = np.append(hdulist[1].data['IVAR'][0], hdulist[2].data['IVAR'][0])
data.add_component(full_wl, 'Wavelength')
data.add_component(full_spec, 'Flux')
data.add_component(1/np.sqrt(full_ivar), 'Uncertainty')
return data
Let’s take a look at how to write this step by step. We first take a look at the contents of our example FITS file to see which parts we need to pass to MOSViz:
>>> from astropy.io import fits
>>> hdulist = fits.open('spec1d.1355.134.13040873.fits')
>>> hdulist.info()
Filename: spec1d.1355.134.13040873.fits
No. Name Type Cards Dimensions Format
0 PRIMARY PrimaryHDU 4 ()
1 Bxspf-B BinTableHDU 131 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
2 Bxspf-R BinTableHDU 131 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
3 Horne-B BinTableHDU 140 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
4 Horne-R BinTableHDU 140 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
5 Bxspf-NL-B BinTableHDU 131 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
6 Bxspf-NL-R BinTableHDU 131 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
7 Horne-NL-B BinTableHDU 140 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
8 Horne-NL-R BinTableHDU 140 1R x 15C [4096E, 4096E, 4096E, 4096I, 4096I, 4096I, 4096I, 4096I, E, E, E, J, J, 4096E, E]
The file contains pairs of red and blue spectra which have been filtered in
various ways. For the sake of this example we’ll choose the Bxspf
spectra.
Let’s take a closer look at the relevant extension:
>>> hdulist['Bxspf-R'].columns
ColDefs(
name = 'SPEC'; format = '4096E'
name = 'LAMBDA'; format = '4096E'
name = 'IVAR'; format = '4096E'
name = 'CRMASK'; format = '4096I'
name = 'BITMASK'; format = '4096I'
name = 'ORMASK'; format = '4096I'
name = 'NBADPIX'; format = '4096I'
name = 'INFOMASK'; format = '4096I'
name = 'OBJPOS'; format = 'E'
name = 'FWHM'; format = 'E'
name = 'NSIGMA'; format = 'E'
name = 'R1'; format = 'J'
name = 'R2'; format = 'J'
name = 'SKYSPEC'; format = '4096E'
name = 'IVARFUDGE'; format = 'E'
)
>>> hdulist['Bxspf-B'].columns
ColDefs(
name = 'SPEC'; format = '4096E'
name = 'LAMBDA'; format = '4096E'
name = 'IVAR'; format = '4096E'
name = 'CRMASK'; format = '4096I'
name = 'BITMASK'; format = '4096I'
name = 'ORMASK'; format = '4096I'
name = 'NBADPIX'; format = '4096I'
name = 'INFOMASK'; format = '4096I'
name = 'OBJPOS'; format = 'E'
name = 'FWHM'; format = 'E'
name = 'NSIGMA'; format = 'E'
name = 'R1'; format = 'J'
name = 'R2'; format = 'J'
name = 'SKYSPEC'; format = '4096E'
name = 'IVARFUDGE'; format = 'E'
)
Again, there are a lot of options but for MOSViz we’re only interested in three
columns: SPEC
, LAMBDA
, IVAR
. Further, MOSViz expects each of the
arrays to be 1 dimensional and of the same size:
>>> hdulist['Bxspf-R'].data['SPEC'].shape
(1, 4096)
>>> hdulist['Bxspf-R'].data['LAMBDA'].shape
(1, 4096)
>>> hdulist['Bxspf-R'].data['IVAR'].shape
(1, 4096)
All of our arrays are the same size but they are stored in 2 dimensional arrays (with the first axis of size 1). So we’ll just take the first (and only) element.
Now that we know what data we want from our FITS files let’s look at how to write the data loader function. The basic structure for a data loader for a 1D spectrum is:
from glue.core import Data
from mosviz.loaders.mos_loaders import mosviz_spectrum1d_loader
@mosviz_spectrum1d_loader('DEIMOS 1D Spectrum')
def deimos_spectrum1D_reader(filename):
# code to read in data here
return data
'DEIMOS 1D Spectrum'
is the label which is how we will identify this loader.
For users familiar with defining glue data factories,
@mosviz_spectrum1d_loader
is equivalent to @data_factory
but additionaly
tells MOSViz that the loader is specifically for a 1D spectrum.
Let’s now focus on what is needed inside the function.
The function itself takes a filename to open as its only argument, so we open
the file and instantiate a Glue Data
object:
hdulist = fits.open(filename)
data = Data(label='1D Spectrum')
Now as above we’re going to open the FITS file. We add the header from the FITS file to the data object:
data.header = hdulist[1].header
As stated above, MOSViz expects the Wavelength, Flux, and Uncertainty to be each
be a single 1D array. We saw that the red and blue ends of the spectrum are
stored in different extensions and that there are stored as 2D arrays. We take
the first component of the each of the red and blue ends of the spectrum and
combine them together. Then we take the full 1D array for each component and
pass them to the ~glue.core.data.Data
object using the
add_component()
method:
full_wl = np.append(hdulist[1].data['LAMBDA'][0], hdulist[2].data['LAMBDA'][0])
full_spec = np.append(hdulist[1].data['SPEC'][0], hdulist[2].data['SPEC'][0])
full_ivar = np.append(hdulist[1].data['IVAR'][0], hdulist[2].data['IVAR'][0])
data.add_component(full_wl, 'Wavelength')
data.add_component(full_spec, 'Flux')
data.add_component(1/np.sqrt(full_ivar), 'Uncertainty')
return data
2D Spectrum Reader¶
The basic structure for the 2D spectrum reader is similar to that for the 1D spectrum reader:
from astropy.io import fits
from glue.core import Data
from mosviz.loaders.mos_loaders import mosviz_spectrum1d_loader
@mosviz_spectrum2d_loader('DEIMOS 2D Spectrum')
def deimos_spectrum2D_reader(filename):
"""
Data loader for Keck/DEIMOS 2D spectra.
This loads only the Flux and Inverse variance. Wavelength information
comes from the WCS.
"""
hdulist = fits.open(filename)
data = Data(label='2D Spectrum')
data.coords = coordinates_from_header(hdulist[1].header)
data.header = hdulist[1].header
data.add_component(hdulist[1].data['FLUX'][0], 'Flux')
data.add_component(1/np.sqrt(hdulist[1].data['IVAR'][0]), 'Uncertainty')
return data
MOSViz expects the 2D Spectrum Data object to have two components: Flux and Uncertainty. Since a 2D spectrum is an image it also expects a World Coordinate System (WCS) which tells it how to transform from pixels to Wavelength. Let’s take a look at the contents of our example FITS file to see which parts we need to pass to MOSViz:
>>> from astropy.io import fits
>>> hdulist = fits.open('slit.1355.134B.fits.gz')
>>> hdulist.info()
Filename: slit.1153.147B.fits.gz
No. Name Type Cards Dimensions Format
0 PRIMARY PrimaryHDU 4 ()
1 slit BinTableHDU 106 1R x 11C [241664E, 241664E, 241664B, 241664B, 4096E, 241664E, 6D, 3D, 59E, 177E, 241664J]
2 slit BinTableHDU 98 531R x 5C [E, E, E, E, B]
>>> hdulist[1].data.columns
ColDefs(
name = 'FLUX'; format = '241664E'; dim = '( 4096, 59)'
name = 'IVAR'; format = '241664E'; dim = '( 4096, 59)'
name = 'MASK'; format = '241664B'; dim = '( 4096, 59)'
name = 'CRMASK'; format = '241664B'; dim = '( 4096, 59)'
name = 'LAMBDA0'; format = '4096E'
name = 'DLAMBDA'; format = '241664E'; dim = '( 4096, 59)'
name = 'LAMBDAX'; format = '6D'
name = 'TILTX'; format = '3D'
name = 'SLITFN'; format = '59E'
name = 'DLAM'; format = '177E'; dim = '( 59, 3)'
name = 'INFOMASK'; format = '241664J'; dim = '( 4096, 59)'
)
>>> hdulist[2].data.columns
ColDefs(
name = 'AMP'; format = 'E'
name = 'CEN'; format = 'E'
name = 'SIG'; format = 'E'
name = 'BASE'; format = 'E'
name = 'MASK'; format = 'B'
)
MOSViz needs Flux and Uncertainty so the relevant columns are FLUX
and
IVAR
in the the first slit
extension:
>>> hdulist[1].data['FLUX'].shape
(1, 59, 4096)
>>> hdulist[1].data['IVAR'].shape
(1, 59, 4096)
>>>
All of our arrays are the same size but they are stored in 3 dimensional arrays (with the first axis of size 1). So we’ll just take the first (and only) element which will give a 2D array.
We also need a WCS which should be in the header of the same extension as the data:
>>> from astropy.wcs import WCS
>>> WCS(hdulist[1].header)
Number of WCS axes: 2
CTYPE : 'LAMBDA' 'LAMBDA'
CRVAL : 6450.6538154 0.0
CRPIX : 0.0 0.0
CD1_1 CD1_2 : 0.32103118300400002 0.0
CD2_1 CD2_2 : 0.0 1.0
NAXIS : 4367352 1
The WCS is here; however, the two axes both have name ‘LAMBDA’ and if we look at
look at the second coordinate we can see that it isn’t actually transformed.
Glue expects that all of a Data
object’s components (including WCS axes) have
unique names. We can take care of this easily in the data loader function.
Now that we know what data we want from our FITS files let’s look at how to write the data loader function. As before, we use the following decorator to tell glue that this is a data loader, and MOSViz that it can read in 2D spectra:
@mosviz_spectrum2d_loader('DEIMOS 2D Spectrum')
def deimos_spectrum2D_reader(filename):
The function itself takes a filename to open as its only argument. We open the
data file and instantiate a Data
object:
hdulist = fits.open(filename)
data = Data(label='2D Spectrum')
As we noted above, the WCS axes should have different names. Since the second
axis is not transformed we’ll just change the header keyword which specifies its
name to ‘Spatial Y’ Then we set the coords
attribute of the Data
object with
glue.core.coordinates.coordinates_from_wcs()
. We also pass the FITS header to the data so that useful
information can be displayed in the MOSViz:
hdulist[1].header['CTYPE2'] = 'Spatial Y'
data.coords = coordinates_from_wcs(WCS(hdulist[1].header))
data.header = hdulist[1].header
As stated above, MOSViz expects the Flux and Uncertainty to be each be a single
2D array. We take the first component of each array (a 2D array) pass them to
the ~glue.core.data.Data
object using the add_component()
method:
data.add_component(hdulist[1].data['FLUX'][0], 'Flux')
data.add_component(1/np.sqrt(hdulist[1].data['IVAR'][0]), 'Uncertainty')
return data
Cutout Image Reader¶
Finally, the custom reader for the image cutouts looks like:
from astropy.io import fits
from glue.core import Data
from mosviz.loaders.mos_loaders import mosviz_cutout_loader
@mosviz_cutout_loader('ACS Cutout Image')
def acs_cutout_image_reader(filename):
"""
Data loader for the ACS cut-outs for the DEIMOS spectra.
The cutouts contain only the image.
"""
hdulist = fits.open(filename)
data = Data(label='ACS Cutout Image')
data.coords = coordinates_from_header(hdulist[0].header)
data.header = hdulist[0].header
data.add_component(hdulist[0].data, 'Flux')
return data
MOSViz expects the Cutout Image Data object to have one component: Flux. Since it is an image it also expects a World Coordinate System (WCS) which tells it how to transform from pixels to sky coordinates. Let’s take a look at the contents of our example FITS file to see which parts we need to pass to MOSViz.
>>> from astropy.io import fits
>>> hdulist = fits.open('12020821.acs.i_6ac_.fits')
>>> hdulist.info()
Filename: 12020821.acs.i_6ac_.fits
No. Name Type Cards Dimensions Format
0 PRIMARY PrimaryHDU 71 (201, 201) float32
>>> hdulist[0].data.shape
(201, 201)
There is only one extensions and the data in it is the cutout image (a 2D array). We also need a WCS which should be in the header of the same extension as the data:
>>> from astropy.wcs import WCS
>>> WCS(hdulist[0].header)
WCS Keywords
Number of WCS axes: 2
CTYPE : 'RA---TAN' 'DEC--TAN'
CRVAL : 214.40388488799999 52.630077362100003
CRPIX : 101.70472905800101 100.94206076200101
CD1_1 CD1_2 : -8.3333331279300006e-06 -4.5781947460699999e-14
CD2_1 CD2_2 : -4.5781947460699999e-14 8.3333331279300006e-06
NAXIS : 201 201
The WCS looks as we would expect. Now that we know what data we want from our FITS files let’s look at how to write the data loader function. We use the following decorator on the function to tell glue that this is a data factory and to tell MOSViz that it can handle cutout images:
@mosviz_cutout_loader('ACS Cutout Image')
def acs_cutout_image(filename):
The function itself takes a filename to open as its only argument. We open the
data file and instantiate a Data
object:
hdulist = fits.open(filename)
data = Data(label='Cutout Image')
We set the coords
attribute of the Data
object with glue.core.coordinates.coordinates_from_wcs()
.
We also pass the FITS header to the data so that useful information can be
displayed in the MOSViz:
data.coords = coordinates_from_wcs(WCS(hdulist[0].header))
data.header = hdulist[0].header
We take the data in first extension data array (a 2D array) and pass it to the
~glue.core.data.Data
object using the add_component()
method:
data.add_component(hdulist[0].data, 'Flux')
return data
Summary¶
The full contents of the ~/.glue/config.py is shown below:
import numpy as np
from astropy.io import fits
from astropy.wcs import WCS
from glue.core import Data
from glue.core.coordinates import coordinates_from_header, coordinates_from_wcs
from mosviz.loaders.mos_loaders import (mosviz_spectrum1d_loader,
mosviz_spectrum2d_loader,
mosviz_cutout_loader)
@mosviz_spectrum1d_loader('DEIMOS 1D Spectrum')
def deimos_spectrum1D_reader(filename):
"""
Data loader for Keck/DEIMOS 1D spectra.
This loads the 'Bxspf-B' (extension 1)
and 'Bxspf-R' (extension 2) and appends them
together to proudce the combined Red/Blue Spectrum
along with their Wavelength and Inverse Variance
arrays.
"""
hdulist = fits.open(filename)
data = Data(label='1D Spectrum')
data.header = hdulist[1].header
full_wl = np.append(hdulist[1].data['LAMBDA'][0], hdulist[2].data['LAMBDA'][0])
full_spec = np.append(hdulist[1].data['SPEC'][0], hdulist[2].data['SPEC'][0])
full_ivar = np.append(hdulist[1].data['IVAR'][0], hdulist[2].data['IVAR'][0])
data.add_component(full_wl, 'Wavelength')
data.add_component(full_spec, 'Flux')
data.add_component(1/np.sqrt(full_ivar), 'Uncertainty')
return data
@mosviz_spectrum2d_loader('DEIMOS 2D Spectrum')
def deimos_spectrum2D_reader(filename):
"""
Data loader for Keck/DEIMOS 2D spectra.
This loads only the Flux and Inverse variance.
Wavelength information comes from the WCS.
"""
hdulist = fits.open(filename)
data = Data(label='2D Spectrum')
data.coords = coordinates_from_header(hdulist[1].header)
data.header = hdulist[1].header
data.add_component(hdulist[1].data['FLUX'][0], 'Flux')
data.add_component(1/np.sqrt(hdulist[1].data['IVAR'][0]), 'Uncertainty')
return data
@mosviz_cutout_loader('ACS Cutout Image')
def acs_cutout_image_reader(filename):
"""
Data loader for the ACS cut-outs for the DEIMOS spectra.
The cutouts contain only the image.
"""
hdulist = fits.open(filename)
data = Data(label='ACS Cutout Image')
data.coords = coordinates_from_header(hdulist[0].header)
data.header = hdulist[0].header
data.add_component(hdulist[0].data, 'Flux')
return data
Writing the Data Table¶
As mentioned above, when adding a dataset to the MOSViz viewer, you will be prompted to select column names and data loaders, but you can optionally encode these into the catalog metadata to save time. Note that not all file formats will support this kind of meta-data, so if you want to do this you will be restricted to certain formats for the catalog.
The main requirement is that when read in with the Table
read()
method, the Table
meta
attribute should be a dictionary that contains
a loaders
key and a special_columns
key:
Table.meta['loaders']
should then be a dictionary that contains three keys -spectrum1d
,spectrum2d
, andcutout
, and for each of these gives, as a string, the label of the reader to use.Table.meta['special_columns']
should be a dictionary that contains one key/value pair for each special column listed in the table in Overview, where the key is the Default name given in the table and the value is the name of the actual column in the table.
Note that any metadata where the defaults are fine can be omitted. For example, for the special columns, if the actual name is the same as the default name, the key and value will be the same and can be ommitted from the metadata.
As an example, the following ECSV table header indicates the loaders to use, but does not list the special columns explicitly since they already have the expected names:
# %ECSV 0.9
# ---
# meta:
# loaders:
# spectrum1d: "DEIMOS 1D Spectrum"
# spectrum2d: "DEIMOS 2D Spectrum"
# cutout: "ACS Cutout Image"
# datatype:
# - {name: id, datatype: string}
# - {name: ra, unit: deg, datatype: float64}
# - {name: dec, unit: deg, datatype: float64}
# - {name: spectrum2d, datatype: string}
# - {name: spectrum1d, datatype: string}
# - {name: cutout, datatype: string}
# - {name: slit_width, unit: arcsec, datatype: float64}
# - {name: slit_length, unit: arcsec, datatype: float64}
# - {name: pix_scale, datatype: float64}
id ra dec spectrum2d spectrum1d cutout slit_width slit_length pix_scale
deimos_12004808 214.21968 52.410386 Spectra/slit.1153.151R.fits.gz Spectra/spec1d.1153.151.12004808.fits Cutouts/12004808.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12008179 214.33785 52.454369 Spectra/slit.1203.063R.fits.gz Spectra/spec1d.1203.063.12008179.fits Cutouts/12008179.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12012573 214.34313 52.53112 Spectra/slit.1205.091R.fits.gz Spectra/spec1d.1205.091.12012573.fits Cutouts/12012573.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12016058 214.52242 52.580972 Spectra/slit.1208.055R.fits.gz Spectra/spec1d.1208.055.12016058.fits Cutouts/12016058.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12020734 214.49056 52.632246 Spectra/slit.1209.080R.fits.gz Spectra/spec1d.1209.080.12020734.fits Cutouts/12020734.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12020387 214.57266 52.642585 Spectra/slit.1210.072R.fits.gz Spectra/spec1d.1210.072.12020387.fits Cutouts/12020387.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12020049 214.62085 52.646039 Spectra/slit.1211.061R.fits.gz Spectra/spec1d.1211.061.12020049.fits Cutouts/12020049.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12019995 214.69602 52.631649 Spectra/slit.1212.038R.fits.gz Spectra/spec1d.1212.038.12019995.fits Cutouts/12019995.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12019653 214.77361 52.662353 Spectra/slit.1214.026R.fits.gz Spectra/spec1d.1214.026.12019653.fits Cutouts/12019653.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12008349 214.249 52.460424 Spectra/slit.1243.030R.fits.gz Spectra/spec1d.1243.030.12008349.fits Cutouts/12008349.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12012586 214.37004 52.52134 Spectra/slit.1243.079R.fits.gz Spectra/spec1d.1243.079.12012586.fits Cutouts/12012586.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12004455 214.27608 52.408039 Spectra/slit.1244.010R.fits.gz Spectra/spec1d.1244.010.12004455.fits Cutouts/12004455.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_11051203 214.33513 52.381078 Spectra/slit.1246.011R.fits.gz Spectra/spec1d.1246.011.11051203.fits Cutouts/11051203.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12011504 214.61256 52.551567 Spectra/slit.1246.152R.fits.gz Spectra/spec1d.1246.152.12011504.fits Cutouts/12011504.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12024856 214.5929 52.718354 Spectra/slit.1252.066R.fits.gz Spectra/spec1d.1252.066.12024856.fits Cutouts/12024856.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13004306 214.77715 52.814133 Spectra/slit.1253.152R.fits.gz Spectra/spec1d.1253.152.13004306.fits Cutouts/13004306.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12024118 214.73955 52.697049 Spectra/slit.1254.094R.fits.gz Spectra/spec1d.1254.094.12024118.fits Cutouts/12024118.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_12020067 214.64333 52.632145 Spectra/slit.1255.041R.fits.gz Spectra/spec1d.1255.041.12020067.fits Cutouts/12020067.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13019968 214.77751 52.910775 Spectra/slit.1302.115R.fits.gz Spectra/spec1d.1302.115.13019968.fits Cutouts/13019968.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13026888 215.01438 52.949334 Spectra/slit.1306.072R.fits.gz Spectra/spec1d.1306.072.13026888.fits Cutouts/13026888.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13026873 215.0064 52.95921 Spectra/slit.1306.077R.fits.gz Spectra/spec1d.1306.077.13026873.fits Cutouts/13026873.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13026857 214.95442 52.969926 Spectra/slit.1306.094R.fits.gz Spectra/spec1d.1306.094.13026857.fits Cutouts/13026857.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13026107 215.10585 53.003483 Spectra/slit.1308.070R.fits.gz Spectra/spec1d.1308.070.13026107.fits Cutouts/13026107.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13025290 215.19495 52.963721 Spectra/slit.1309.034R.fits.gz Spectra/spec1d.1309.034.13025290.fits Cutouts/13025290.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13043017 215.10605 53.116245 Spectra/slit.1311.114R.fits.gz Spectra/spec1d.1311.114.13043017.fits Cutouts/13043017.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13051276 215.10065 53.128093 Spectra/slit.1311.121R.fits.gz Spectra/spec1d.1311.121.13051276.fits Cutouts/13051276.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13041627 215.31852 53.104803 Spectra/slit.1313.048R.fits.gz Spectra/spec1d.1313.048.13041627.fits Cutouts/13041627.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13050572 215.17647 53.154515 Spectra/slit.1313.104R.fits.gz Spectra/spec1d.1313.104.13050572.fits Cutouts/13050572.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13050507 215.14259 53.169163 Spectra/slit.1313.120R.fits.gz Spectra/spec1d.1313.120.13050507.fits Cutouts/13050507.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13058235 215.23847 53.184374 Spectra/slit.1314.098R.fits.gz Spectra/spec1d.1314.098.13058235.fits Cutouts/13058235.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13049212 215.38783 53.136419 Spectra/slit.1315.047R.fits.gz Spectra/spec1d.1315.047.13049212.fits Cutouts/13049212.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13049133 215.3953 53.156244 Spectra/slit.1315.052R.fits.gz Spectra/spec1d.1315.052.13049133.fits Cutouts/13049133.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13058203 215.27553 53.210001 Spectra/slit.1315.105R.fits.gz Spectra/spec1d.1315.105.13058203.fits Cutouts/13058203.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13018671 214.95738 52.921481 Spectra/slit.1343.084R.fits.gz Spectra/spec1d.1343.084.13018671.fits Cutouts/13018671.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13026879 215.00536 52.95371 Spectra/slit.1343.108R.fits.gz Spectra/spec1d.1343.108.13026879.fits Cutouts/13026879.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13034580 215.08674 53.055397 Spectra/slit.1352.022R.fits.gz Spectra/spec1d.1352.022.13034580.fits Cutouts/13034580.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13058164 215.26445 53.18501 Spectra/slit.1352.117R.fits.gz Spectra/spec1d.1352.117.13058164.fits Cutouts/13058164.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13040952 215.32582 53.068148 Spectra/slit.1355.091R.fits.gz Spectra/spec1d.1355.091.13040952.fits Cutouts/13040952.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
deimos_13040873 215.40401 53.11767 Spectra/slit.1355.134R.fits.gz Spectra/spec1d.1355.134.13040873.fits Cutouts/13040873.acs.v_6ac_.fits 0.2 3.3 0.0 0.66
If the ra/dec columns had a different name in the table, the header should instead look like e.g:
# %ECSV 0.9
# ---
# meta:
# loaders:
# spectrum1d: "DEIMOS 1D Spectrum"
# spectrum2d: "DEIMOS 2D Spectrum"
# cutout: "ACS Cutout Image"
# special_columns:
# ra: ra_j2000
# dec: dec_j2000
# datatype:
# - {name: id, datatype: string}
# - {name: ra_j2000, unit: deg, datatype: float64}
# - {name: dec_j2000, unit: deg, datatype: float64}
...