Simulating DESI Spectra

The goal of this notebook is to demonstrate how to generate some simple DESI spectra using the quickgen utility. For simplicity we will only generate 1D spectra and skip the more computationally intensive (yet still instructive!) step of extracting 1D spectra from simulated 2D spectra (i.e., so-called "pixel-level simulations").

For additional (albeit somewhat outdated) information and documentation about quickgen see
https://desi.lbl.gov/DocDB/cgi-bin/private/ShowDocument?docid=1429

The heart of quickgen is the SpecSim package, which you can read out here:
http://specsim.readthedocs.io/en/stable

If you identify any errors or have requests for additional functionality please create a new issue on
https://github.com/desihub/desisim/issues or send a note to desi-data@desi.lbl.gov.

Getting started.

First, import all the package dependencies.


In [1]:
import os
import numpy as np

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

In [2]:
import desispec.io
import desisim.io
from desisim.obs import new_exposure
from desisim.scripts import quickgen
from desispec.scripts import group_spectra


WARNING:log.py:19:get_logger: desispec.log is deprecated, please use desiutil.log.
WARNING:log.py:19:get_logger: desispec.log is deprecated, please use desiutil.log.
WARNING:log.py:19:get_logger: desispec.log is deprecated, please use desiutil.log.
/usr/local/anaconda3/envs/desi/lib/python3.5/site-packages/matplotlib/__init__.py:1401: UserWarning:  This call to matplotlib.use() has no effect
because the backend has already been chosen;
matplotlib.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

  warnings.warn(_use_error_msg)

In [3]:
%pylab inline


Populating the interactive namespace from numpy and matplotlib

Check and set your environment

Next, make sure we have all the right environment variables set (assuming the bash shell). If any of these environment variables are missing please set them in your .bashrc file (and then restart this notebook) or create them for just this notebook session using the %set_env magic command, as we demonstrate below.


In [4]:
def check_env():
    for env in ('DESIMODEL', 'DESI_ROOT', 'DESI_SPECTRO_SIM', 'DESI_SPECTRO_DATA', 
            'DESI_SPECTRO_REDUX', 'SPECPROD', 'PIXPROD'):
        if env in os.environ:
            print('{} environment set to {}'.format(env, os.getenv(env)))
        else:
            print('Required environment variable {} not set!'.format(env))

In [5]:
check_env()


DESIMODEL environment set to /Users/ioannis/repos/desihub/desimodel
DESI_ROOT environment set to /Users/ioannis/research/projects/desi
DESI_SPECTRO_SIM environment set to /Users/ioannis/research/projects/desi/spectro/sim
DESI_SPECTRO_DATA environment set to /Users/ioannis/research/projects/desi/spectro/data
DESI_SPECTRO_REDUX environment set to /Users/ioannis/research/projects/desi/spectro/redux
SPECPROD environment set to dailytest
PIXPROD environment set to dailytest

Let's reassign the $SPECPROD environment to something other than dailytest so that we don't conflict with the outputs of the standard DESI integration test. In addition, we need to make raw data input $DESI_SPECTO_DATA match $DESI_SPECTRO_SIM/$PIXPROD where the simulated data will be written.


In [6]:
%set_env SPECPROD=example
%set_env PIXPROD=example
rawdata_dir = desisim.io.simdir()
%set_env DESI_SPECTRO_DATA=$rawdata_dir

print('Simulated raw data will be written to {}'.format(desisim.io.simdir()))
print('Pipeline will read raw data from {}'.format(desispec.io.rawdata_root()))
print('    (without knowing that it was simulated)')
print('Pipeline will write processed data to {}'.format(desispec.io.specprod_root()))


env: SPECPROD=example
env: PIXPROD=example
env: DESI_SPECTRO_DATA=/Users/ioannis/research/projects/desi/spectro/sim/example/
Simulated raw data will be written to /Users/ioannis/research/projects/desi/spectro/sim/example/
Pipeline will read raw data from /Users/ioannis/research/projects/desi/spectro/sim/example/
    (without knowing that it was simulated)
Pipeline will write processed data to /Users/ioannis/research/projects/desi/spectro/redux/example

Specify the parameters of the simulation.

Next, let's specify the number and spectral type distribution of spectra we want to simulate, and the random seed. Setting the seed here (which can be any number at all!) ensures that your simulations are reproducible. Let's also explicitly set the night of the "observations" (the default is to use the current date) and the expid or exposure ID number (which would allow you to simulate more than one DESI exposure).

The flavor option is used to choose the correct sky-brightness model and it also determines the distribution of targets for a given flavor. For example, flavor='dark' returns the right relative sampling density of ELGs, LRGs, and QSOs. The other available (science target) options for flavor are 'dark', 'gray', 'grey', 'bright', 'bgs', 'mws', 'lrg', 'elg', 'qso', and 'std'. (You can also set flavor to either 'arc' or 'flat' but that would be boring!)


In [7]:
nspec = 100
seed = 555
flavor = 'dark'
night = '20170615'
expid = 0

Generating noiseless spectra.

The first step is to generate the fibermap and simspec files needed by quickgen. The fibermap table contains (simulated) information about the position of each target in the DESI focal plane, while the simspec table holds the "truth" spectra and the intrinsic properties of each object (redshift, noiseless photometry, [OII] flux, etc.).

In detail, the simspec and fibermap data models are described at

To generate these files we'll use new_exposure, a convenience function for generating random typical exposures of various types for testing. However, note that new_exposure isn't intended for every possible analysis; if you want to use your own mix of objects, you just need to write your own fibermap and simspec files following that format instead of calling new_exposure.

Note that in our call to new_exposure, the tileid and exptime (exposure time) optional inputs are shown for demonstration purposes but do not need to be explicitly set. In particular, the default exposure time is based on the value specified in the $DESIMODEL/data/desi.yaml parameter file.

Note: The simspec file format may change in the near future, so structure your code to separate generating spectra from the code for writing these particular formats.


In [8]:
fibermap, truth = new_exposure(flavor=flavor, nspec=nspec, seed=seed, night=night, 
                               expid=expid, tileid=None, exptime=None)


INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/elg_templates_v2.0.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/elg_templates_v2.0.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/lrg_templates_v1.3.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/elg_templates_v2.0.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/elg_templates_v2.0.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/lrg_templates_v1.3.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/lrg_templates_v1.3.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/lrg_templates_v1.3.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:io.py:625:read_basis_templates: Reading /Users/ioannis/research/projects/desi/spectro/templates/basis_templates/v2.3/star_templates_v2.1.fits
INFO:obs.py:226:new_exposure: skyfile /Users/ioannis/repos/desihub/desimodel/data/spectra/spec-sky.dat
INFO:obs.py:297:new_exposure: Wrote /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/fibermap-00000000.fits
INFO:obs.py:305:new_exposure: Wrote /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/simspec-00000000.fits

Reading the fibermap and spectral metadata

First, let's see what got written to the raw data directory as a result of that last command.


In [9]:
rawdata_dir = desispec.io.rawdata_root()
!find $rawdata_dir | sort


/Users/ioannis/research/projects/desi/spectro/sim/example/
/Users/ioannis/research/projects/desi/spectro/sim/example//20170615
/Users/ioannis/research/projects/desi/spectro/sim/example//20170615/fibermap-00000000.fits
/Users/ioannis/research/projects/desi/spectro/sim/example//20170615/simspec-00000000.fits
/Users/ioannis/research/projects/desi/spectro/sim/example//etc
/Users/ioannis/research/projects/desi/spectro/sim/example//etc/obslog.sqlite

Let's go a step further and read the fibermap and simspec files from on-disk.

Note that in general code should not generate filepaths by hand, but rather call desispec.io.findfile to find the file it needs. If you need to override the standard environment variable locations, you can use the outdir option, while still letting it construct the canonical filename for each type of file.


In [10]:
fiberfile = desispec.io.findfile('fibermap', night=night, expid=expid)
simspecfile = desisim.io.findfile('simspec', night=night, expid=expid)

In [11]:
print('Reading fibermap file {}'.format(fiberfile))
hdu = fits.open(fiberfile)
hdu.info()
fibermap = Table(hdu['FIBERMAP'].data)
hdu.close()


Reading fibermap file /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/fibermap-00000000.fits
Filename: /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/fibermap-00000000.fits
No.    Name         Type      Cards   Dimensions   Format
  0  PRIMARY     PrimaryHDU       6   ()      
  1  FIBERMAP    BinTableHDU     98   100R x 26C   [10A, 20A, 8A, K, K, K, K, 5E, 50A, J, K, J, J, J, J, E, D, D, D, D, D, D, D, D, E, E]   

In [12]:
fibermap[:3]


Out[12]:
<Table length=3>
OBJTYPETARGETCATBRICKNAMETARGETIDDESI_TARGETBGS_TARGETMWS_TARGETMAG [5]FILTER [5]SPECTROIDPOSITIONERLOCATIONDEVICE_LOCPETAL_LOCFIBERLAMBDAREFRA_TARGETDEC_TARGETRA_OBSDEC_OBSX_TARGETY_TARGETX_FVCOBSY_FVCOBSY_FVCERRX_FVCERR
str10str20str8int64int64int64int64float32str10int32int64int32int32int32int32float32float64float64float64float64float64float64float64float64float32float32
ELG3331p155592041473521903995120023.1645 .. 21.7528DECAM_G .. WISE_W20959595005400.0333.23750387515.5578749931333.23750387515.5578749931-4.13464340313-176.016389199-4.13464340313-176.0163891990.00.0
ELG3334p155552308044078250153920022.9234 .. 22.1754DECAM_G .. WISE_W20626262015400.0333.41313796415.4815165289333.41313796415.4815165289-45.5863791815-157.134697634-45.5863791815-157.1346976340.00.0
ELG3334p157706756809220058901720021.8622 .. 21.6234DECAM_G .. WISE_W20102102102025400.0333.42389365815.631559969333.42389365815.631559969-48.26471976-194.58679079-48.26471976-194.586790790.00.0

In [13]:
print('Reading simspec file {}.'.format(simspecfile))
hdu = fits.open(simspecfile)
hdu.info()
meta = Table(hdu['METADATA'].data)
hdu.close()


Reading simspec file /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/simspec-00000000.fits.
Filename: /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/simspec-00000000.fits
No.    Name         Type      Cards   Dimensions   Format
  0  PRIMARY     PrimaryHDU      15   ()      
  1  WAVE        ImageHDU         9   (31901,)   float64   
  2  FLUX        ImageHDU         9   (31901, 100)   float32   
  3  SKYFLUX     ImageHDU         8   (31901,)   float32   
  4  WAVE_B      ImageHDU         9   (12326,)   float64   
  5  PHOT_B      ImageHDU         8   (12326, 100)   float32   
  6  SKYPHOT_B   ImageHDU         7   (12326,)   float32   
  7  WAVE_R      ImageHDU         9   (11205,)   float64   
  8  PHOT_R      ImageHDU         8   (11205, 100)   float32   
  9  SKYPHOT_R   ImageHDU         7   (11205,)   float32   
 10  WAVE_Z      ImageHDU         9   (12765,)   float64   
 11  PHOT_Z      ImageHDU         8   (12765, 100)   float32   
 12  SKYPHOT_Z   ImageHDU         7   (12765,)   float32   
 13  METADATA    BinTableHDU     61   100R x 24C   [10A, 10A, J, K, E, E, 6E, 2E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E]   

In [14]:
meta[:3]


Out[14]:
<Table length=3>
OBJTYPESUBTYPETEMPLATEIDSEEDREDSHIFTMAGDECAM_FLUX [6]WISE_FLUX [2]OIIFLUXHBETAFLUXEWOIIEWHBETAD4000VDISPOIIDOUBLETOIIIHBETAOIIHBETANIIHBETASIIHBETAZMETALAGETEFFLOGGFEH
str10str10int32int64float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32float32
ELG351232441137391.2583822.9370.441517 .. 1.321432.19795 .. 1.990198.25246e-17-1.073.3845-1.01.0065268.26610.733237-0.08507860.275525-0.248196-0.19466-1.0-1.0-1.0-1.0-1.0
ELG495139525051390.82080422.63490.616534 .. 1.591982.13285 .. 1.348484.69683e-17-1.025.1577-1.01.0336640.17240.757255-0.008850630.630011-0.265495-0.230491-1.0-1.0-1.0-1.0-1.0
ELG69283697206211.1161921.87461.64478 .. 2.4872.91573 .. 2.24211.45983e-16-1.048.7059-1.00.99021340.17240.698619-0.003542480.468131-0.177077-0.244851-1.0-1.0-1.0-1.0-1.0

Make a simple plot

Here's a fun simple plot of the redshift histogram distributions. Now you try!


In [15]:
allobjtype = meta['OBJTYPE']
redlim = (-0.2, 1.1*meta['REDSHIFT'].max())
fig, ax = plt.subplots()
for objtype in sorted(set(allobjtype)):
    indx = objtype == allobjtype
    hh = ax.hist(meta['REDSHIFT'][indx], bins=nspec//3, 
                 label=objtype, alpha=0.5, range=redlim)
ax.set_xlabel('Redshift')
ax.set_ylabel('Number of Simulated Spectra')
ax.legend(loc='upper right', ncol=3)
ax.margins(0.2)
ax.set_xlim(redlim)


Out[15]:
(-0.2, 2.3472768068313599)

Simulating spectra using quickgen.

We're now ready to simulate DESI spectra using quickgen! Since we're calling quickgen from within this notebook (rather than from the command line in a terminal) we have to parse the simspec and fibermap filename inputs first.

quickgen generates four types of files and writes them to the \$DESI_SPECTRO_REDUX/\$SPECPROD/exposures directory: calib, sky, cframe, and frame files. We will use the cframe, or calibrated frame files, which contain the flux-calibrated and sky-subtracted DESI spectra (one file per brz camera and spectrograph).

The data model and the other files and their contents are documented here:
http://desidatamodel.readthedocs.io/en/latest/DESI_SPECTRO_REDUX/PRODNAME/exposures/NIGHT/EXPID/index.html

The code in the following cell calls the equivalent of the command line:

quickgen --simspec {simspecfile} --fibermap {fiberfile}

In [16]:
args = quickgen.parse([
    '--simspec', simspecfile,
    '--fibermap', fiberfile
])
quickgen.main(args)


INFO:quickgen.py:242:main: Reading fibermap file /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/fibermap-00000000.fits
INFO:quickgen.py:275:main: Initializing SpecSim with config desi
INFO:quickgen.py:281:main: Reading input file /Users/ioannis/research/projects/desi/spectro/sim/example/20170615/simspec-00000000.fits
INFO:quickgen.py:672:main: Writing files for channel:b, spectrograph:0, spectra:0 to 100
INFO:quickgen.py:699:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-b0-00000000.fits
INFO:quickgen.py:717:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-b0-00000000.fits
INFO:quickgen.py:732:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-b0-00000000.fits
INFO:quickgen.py:753:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-b0-00000000.fits
INFO:quickgen.py:672:main: Writing files for channel:r, spectrograph:0, spectra:0 to 100
WARNING: VerifyWarning: Card is too long, comment will be truncated. [astropy.io.fits.card]
INFO:quickgen.py:699:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-r0-00000000.fits
INFO:quickgen.py:717:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-r0-00000000.fits
INFO:quickgen.py:732:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-r0-00000000.fits
INFO:quickgen.py:753:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-r0-00000000.fits
INFO:quickgen.py:672:main: Writing files for channel:z, spectrograph:0, spectra:0 to 100
INFO:quickgen.py:699:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-z0-00000000.fits
INFO:quickgen.py:717:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-z0-00000000.fits
INFO:quickgen.py:732:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-z0-00000000.fits
INFO:quickgen.py:753:main: Wrote file /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-z0-00000000.fits

Inspect the output cframe files

Let's briefly look at one of the cframe files for the blue camera using desispec.io.frame.read_frame, which returns a Frame class with all the attributes you might want.


In [17]:
cframefile = desispec.io.findfile('cframe', night=night, expid=expid, camera='b0')
print('Reading {}'.format(cframefile))
cframe = desispec.io.frame.read_frame(cframefile)


Reading /Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-b0-00000000.fits

In [18]:
dir(cframe)


Out[18]:
['R',
 '__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 'chi2pix',
 'fibermap',
 'fibers',
 'flux',
 'ivar',
 'mask',
 'meta',
 'nspec',
 'nwave',
 'resolution_data',
 'spectrograph',
 'vet',
 'wave']

Let's make a quick plot of the zeroth spectrum.


In [19]:
print(cframe.wave.shape, cframe.flux.shape)


(4760,) (100, 4760)

In [20]:
fig, ax = plt.subplots()
ax.errorbar(cframe.wave, cframe.flux[0, :], 1/np.sqrt(cframe.ivar[0, :]))
ax.set_xlabel('Wavelength (A)')
ax.set_ylabel('Flux ($10^{-17}$ erg/s/cm$^2$)')


Out[20]:
<matplotlib.text.Text at 0x11beed128>

Regrouping the spectra

As you can imagine, working with cframe files is pretty tedious, especially across three cameras, 10 spectrographs, and more than 35 million targets! Therefore, let's combine and reorganize the individual cframe files into spectra files grouped on the sky. Spectra are organized into healpix pixels (here chosen to have nside=64). If you're interested, you can read more about the healpix directory structure here:
https://github.com/desihub/desispec/blob/master/doc/nb/Intro_to_DESI_spectra.ipynb

Regrouping is especially important for real observations with overlapping tiles where the same object could be reobserved on different exposures separated by short or large amounts of time.

TODO: Add the spectra files to desidatamodel.

To regroup the spectra, we will run the (notebook) equivalent of the command:

desi_group_spectra --hpxnside 64

In [21]:
nside = 64
args = group_spectra.parse(['--hpxnside', '{}'.format(nside)])
group_spectra.main(args)


INFO:group_spectra.py:74:main: Starting at Sun Jun 18 11:20:38 2017
INFO:group_spectra.py:75:main:   using raw dir /Users/ioannis/research/projects/desi/spectro/sim/example
INFO:group_spectra.py:76:main:   using spectro production dir /Users/ioannis/research/projects/desi/spectro/redux/example
INFO:group_spectra.py:197:main: Distributing 4 spectral groups among 1 processes
INFO:group_spectra.py:220:main:   (0000) Begin spectral group spectra-64-12609 at Sun Jun 18 11:20:38 2017
INFO:group_spectra.py:294:main:   (0000) End spectral group spectra-64-12609 at Sun Jun 18 11:20:47 2017
INFO:group_spectra.py:220:main:   (0000) Begin spectral group spectra-64-12612 at Sun Jun 18 11:20:47 2017
INFO:group_spectra.py:294:main:   (0000) End spectral group spectra-64-12612 at Sun Jun 18 11:21:36 2017
INFO:group_spectra.py:220:main:   (0000) Begin spectral group spectra-64-19435 at Sun Jun 18 11:21:36 2017
INFO:group_spectra.py:294:main:   (0000) End spectral group spectra-64-19435 at Sun Jun 18 11:22:14 2017
INFO:group_spectra.py:220:main:   (0000) Begin spectral group spectra-64-19438 at Sun Jun 18 11:22:14 2017
INFO:group_spectra.py:294:main:   (0000) End spectral group spectra-64-19438 at Sun Jun 18 11:22:25 2017
INFO:group_spectra.py:301:main: Finishing at Sun Jun 18 11:22:25 2017

Inspect the output (combined and regrouped) spectra

So what did we end up with in the redux output directory?

  • exposures/{night}/{expid}/: individual spectrograph camera spectra ("frames") grouped by night/expid
  • spectra-64/: spectra grouped by healpix location on the sky

In [22]:
reduxdir = desispec.io.specprod_root()
!find $reduxdir | sort


/Users/ioannis/research/projects/desi/spectro/redux/example
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-b0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-r0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/calib-z0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-b0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-r0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/cframe-z0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-b0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-r0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/frame-z0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-b0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-r0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/exposures/20170615/00000000/sky-z0-00000000.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/126
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/126/12609
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/126/12609/spectra-64-12609.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/126/12612
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/126/12612/spectra-64-12612.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194/19435
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194/19435/spectra-64-19435.fits
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194/19438
/Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194/19438/spectra-64-19438.fits

As a quick example, let's plot up the zeroth spectrum in healpix pixel 19435.


In [23]:
specfilename = desispec.io.findfile('spectra', groupname=19435, nside=nside)

In [24]:
print('Reading {}'.format(specfilename))
specobj = desispec.io.read_spectra(specfilename)


Reading /Users/ioannis/research/projects/desi/spectro/redux/example/spectra-64/194/19435/spectra-64-19435.fits

In [25]:
dir(specobj)


Out[25]:
['R',
 '__class__',
 '__delattr__',
 '__dict__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__gt__',
 '__hash__',
 '__init__',
 '__le__',
 '__lt__',
 '__module__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 '__weakref__',
 '_bands',
 '_ftype',
 '_single',
 'bands',
 'extra',
 'fibermap',
 'flux',
 'ftype',
 'ivar',
 'mask',
 'meta',
 'num_spectra',
 'num_targets',
 'resolution_data',
 'select',
 'target_ids',
 'update',
 'wave',
 'wavelength_grid']

In [26]:
specobj.wave.keys(), specobj.flux.keys()


Out[26]:
(dict_keys(['r', 'b', 'z']), dict_keys(['r', 'b', 'z']))

In [27]:
thisone = 0
fig, ax = plt.subplots()
for camera, color in zip( ('b', 'r', 'z'), ('blue', 'red', 'magenta') ):
    ax.plot(specobj.wave[camera], specobj.flux[camera][thisone], color=color)
ax.set_xlabel('Wavelength (A)')
ax.set_ylabel('Flux ($10^{-17}$ erg/s/cm$^2$)')


Out[27]:
<matplotlib.text.Text at 0x11b160828>