Affiliated package for 1D spectral operations. Maintainer: @crawfordsm @keflavich @nmearl
Latest commit 0ddbcea Jun 7, 2017 @bsipocz bsipocz committed on GitHub Merge pull request #154 from bsipocz/ci-helpers_use_generic_script
Use the generic ci-helpers script


Specutils is an Astropy affiliated package with the goal of providing a shared set of Python representations of astronomical spectra and basic tools to operate on these spectra. The effort is also meant to be a "hub", helping to unite the Python astronomical spectroscopy community around shared effort, much as Astropy is meant to for the wider astronomy Python ecosystem.

Note that Specutils is not intended as an all-in-one spectroscopic analysis or reduction tool. While it provides some basic analysis (following the Python philosophy of "batteries included"), it is also meant to facilitate connecting together disparate reduction pipelines and analysis tools through shared data representations.


There are several ways to install the package, the most direct is using pip

$ pip install git+

Otherwise, you may simply clone the repo and install the package

$ git clone
$ cd specutils
$ python install

or, if you'd like to easily be able to pip uninstall, use the following commands

$ git clone
$ cd specutils
$ pip install .


Defining a spectrum is straightforward

from astropy.units import Quantity
from specutils.spectra import Spectrum1D
import numpy as np

# Using Astropy `Quantity`s
spec = Spectrum1D(flux=Quantity(np.random.sample(100), "erg/Angstrom/cm2/s"),
                  dispersion=Quantity(np.arange(100), "Angstrom"))

# Without `Quantity`s
spec = Spectrum1D(flux=np.random.sample(100), unit="erg/Angstrom/cm2/s",
                  dispersion=np.arange(100), disp_unit="Angstrom")

Converting to different units


# From Angstrom to Hz
spec.to_dispersion("Hz", rest=Quantity(202, "Angstrom"))

# From Hz to cm/s
spec.to_dispersion("cm/s", rest=Quantity(1.48412108e+16, "Hz"))

# From cm/s to Angstrom
spec.to_dispersion("Angstrom", rest=Quantity(1.48412108e+16, "Hz"))

Basic analysis usage

from specutils.analysis import equivalent_width


Custom loaders

Define a custom loader in a separate python file and place the file in your ~/.specutils directory. Upon importing specutils, the loader will be added to the registry.

# ~/.specutils/
import os
import six

from import fits
from astropy.nddata import StdDevUncertainty
from astropy.table import Table
from astropy.units import Unit
from astropy.wcs import WCS

from import data_loader
from specutils.spectra import Spectrum1D

# Define an optional identifier. If made specific enough, this circumvents the
# need to add `format="my-format"` in the `` call.
def identify_generic_fits(origin, *args, **kwargs):
    return (isinstance(args[0], six.string_types) and
            os.path.splitext(args[0].lower())[1] == '.fits')

@data_loader("my-format", identifier=identify_generic_fits)
def generic_fits(file_name, **kwargs):
    name = os.path.basename(file_name.rstrip(os.sep)).rsplit('.', 1)[0]

    with, **kwargs) as hdulist:
        header = hdulist[0].header

        tab =

        meta = {'header': header}
        wcs = WCS(hdulist[0].header)
        uncertainty = StdDevUncertainty(tab["err"])
        data = tab["flux"] * Unit("Jy")

    return Spectrum1D(flux=data, wcs=wcs, uncertainty=uncertainty, meta=meta)

Using your custom loader:

from specutils import Spectrum1D

spec ="path/to/data", format="my-format")

Custom writer

Define a custom writer in a separate python file and place the file in your ~/.specutils directory. Upon importing specutils, the writer will be added to the registry.

# ~/.spectacle/
from astropy.table import Table
from import custom_writer

def generic_fits(spectrum, file_name, **kwargs):
    flux = spectrum.flux.value
    disp = spectrum.dispersion.value
    meta = spectrum.meta

    tab = Table([disp, flux], names=("dispersion", "flux"), meta=meta)

    tab.write(file_name, format="fits")

Using your custom writer:

spec = Spectrum1D(flux=Quantity(np.random.sample(100), "erg/Angstrom/cm2/s"),
                  dispersion=Quantity(np.arange(100), "Angstrom"))

spec.write("my_output.fits", format="fits-writer")