File: custom_loading.rst

package info (click to toggle)
specutils 2.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 12,460 kB
  • sloc: python: 13,497; makefile: 111
file content (187 lines) | stat: -rw-r--r-- 5,970 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
*************************************************
Loading and Defining Custom Spectral File Formats
*************************************************

Loading From a File
-------------------

Specutils leverages the astropy io registry to provide an interface for conveniently
loading data from files. To create a custom loader, the user must define it in
a separate python file and place the file in their ``~/.specutils`` directory.

Loading from a FITS File
------------------------
A spectra with a *Linear Wavelength Solution* can be read using the ``read``
method of the :class:`~specutils.Spectrum` class to parse the file name and
format


.. code-block:: python

  import os
  from specutils import Spectrum

  file_path = os.path.join('path/to/folder', 'file_with_1d_wcs.fits')

  spec = Spectrum.read(file_path, format='wcs1d-fits')


This will create a :class:`~specutils.Spectrum` object that you can manipulate later.

For instance, you could plot the spectrum.

.. code-block:: python

  import matplotlib.pyplot as plt

  plt.title('FITS file with 1D WCS')
  plt.xlabel('Wavelength (Angstrom)')
  plt.ylabel('Flux (erg/cm2/s/A)')
  plt.plot(spec.wavelength, spec.flux)
  plt.show()


.. image:: img/read_1d.png


Creating a Custom Loader
------------------------

Defining a custom loader consists of importing the
`~specutils.io.registers.data_loader` decorator from specutils and attaching
it to a function that knows how to parse the user's data.  The return object
of this function must be an instance of one of the spectral classes
(:class:`~specutils.Spectrum`, :class:`~specutils.SpectrumCollection`,
:class:`~specutils.SpectrumList`).

Optionally, the user may define an identifier function. This function acts to
ensure that the data file being loaded is compatible with the loader function.

.. code-block:: python

    # ~/.specutils/my_custom_loader.py
    import os

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

    from specutils.io.registers import data_loader
    from specutils import Spectrum


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


    @data_loader("my-format", identifier=identify_generic_fits,
                 extensions=['fits'])
    def generic_fits(file_name, **kwargs):
        with fits.open(file_name, **kwargs) as hdulist:
            header = hdulist[0].header

            tab = Table.read(file_name)

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

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


An ``extensions`` keyword can be provided. This allows for basic filename
extension matching in the case that the ``identifier`` function is not
provided.

It is possible to query the registry to return the list of loaders associated
with a particular extension.

.. code-block:: python

    from specutils.io import get_loaders_by_extension

    loaders = get_loaders_by_extension('fits')

The returned list contains the format labels that can be fed into the ``format``
keyword argument of the ``Spectrum.read`` method.

After placing this python file in the user's ``~/.specutils`` directory, it
can be utilized by referencing its name in the ``read`` method of the
:class:`~specutils.Spectrum` class

.. code-block:: python

    from specutils import Spectrum

    spec = Spectrum.read("path/to/data", format="my-format")

.. _multiple_spectra:

Loading Multiple Spectra
^^^^^^^^^^^^^^^^^^^^^^^^

It is possible to create a loader that reads multiple spectra from the same
file. For the general case where none of the spectra are assumed to be the same
length, the loader should return a `~specutils.SpectrumList`. Consider the
custom JWST data loader as an example:

.. literalinclude:: ../specutils/io/default_loaders/jwst_reader.py
    :language: python

Note that by default, any loader that uses ``dtype=Spectrum`` will also
automatically add a reader for `~specutils.SpectrumList`. This enables user
code to call `specutils.SpectrumList.read <astropy.nddata.NDIOMixin.read>` in
all cases if it can't make assumptions about whether a loader returns one or
many `~specutils.Spectrum` objects. This method is available since
`~specutils.SpectrumList` makes use of the Astropy IO registry (see
`astropy.io.registry.read`).


.. _custom_writer:

Creating a Custom Writer
------------------------

Similar to creating a custom loader, a custom data writer may also be defined.
This again will be done in a separate python file and placed in the user's
``~/.specutils`` directory to be loaded into the astropy io registry.

.. code-block:: python

    # ~/.spectacle/my_writer.py
    from astropy.table import Table
    from specutils.io.registers import custom_writer


    @custom_writer("fits-writer")
    def generic_fits(spectrum, file_name, **kwargs):
        flux = spectrum.flux.value
        disp = spectrum.spectral_axis.value
        meta = spectrum.meta

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

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

The custom writer can be used by passing the name of the custom writer to the
``format`` argument of the ``write`` method on the
:class:`~specutils.Spectrum`.

.. code-block:: python

    spec = Spectrum(flux=np.random.sample(100) * u.Jy,
                      spectral_axis=np.arange(100) * u.AA)

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


Reference/API
-------------
.. automodapi:: specutils.io.registers
    :no-heading: