CCDData Class¶
Getting Started¶
Getting Data In¶
Creating a CCDData object from any array-like data using
astropy.nddata is convenient:
>>> import numpy as np
>>> from astropy.nddata import CCDData
>>> from astropy.utils.data import get_pkg_data_filename
>>> ccd = CCDData(np.arange(10), unit="adu")
Note that behind the scenes, this creates references to (not copies of) your
data when possible, so modifying the data in ccd will modify the
underlying data.
You are required to provide a unit for your data. The most frequently used
units for these objects are likely to be adu, photon, and electron,
which can be set either by providing the string name of the unit (as in the
example above) or from unit objects:
>>> from astropy import units as u
>>> ccd_photon = CCDData([1, 2, 3], unit=u.photon)
>>> ccd_electron = CCDData([1, 2, 3], unit="electron")
If you prefer not to use the unit functionality, then use the special unit
u.dimensionless_unscaled when you create your CCDData
images:
>>> ccd_unitless = CCDData(np.zeros((10, 10)),
... unit=u.dimensionless_unscaled)
A CCDData object can also be initialized from a FITS filename
or URL:
>>> ccd = CCDData.read('my_file.fits', unit="adu")
>>> ccd = CCDData.read(get_pkg_data_filename('tutorials/FITS-images/HorseHead.fits'), unit="adu", cache=True)
If there is a unit in the FITS file (in the BUNIT keyword), that will be
used, but explicitly providing a unit in read will override any unit in the
FITS file.
There is no restriction at all on what the unit can be — any unit in
astropy.units or another that you create yourself will work.
In addition, the user can specify the extension in a FITS file to use:
>>> ccd = CCDData.read('my_file.fits', hdu=1, unit="adu")
If hdu is not specified, it will assume the data is in the primary
extension. If there is no data in the primary extension, the first extension
with image data will be used.
Metadata¶
When initializing from a FITS file, the header property is initialized using
the header of the FITS file. Metadata is optional, and can be provided by any
dictionary or dict-like object:
>>> ccd_simple = CCDData(np.arange(10), unit="adu")
>>> my_meta = {'observer': 'Edwin Hubble', 'exposure': 30.0}
>>> ccd_simple.header = my_meta # or use ccd_simple.meta = my_meta
Whether the metadata is case-sensitive or not depends on how it is initialized. A FITS header, for example, is not case-sensitive, but a Python dictionary is.
Getting Data Out¶
A CCDData object behaves like a numpy array (masked if the
CCDData mask is set) in expressions, and the underlying
data (ignoring any mask) is accessed through the data attribute:
>>> ccd_masked = CCDData([1, 2, 3], unit="adu", mask=[0, 0, 1])
>>> 2 * np.ones(3) * ccd_masked # one return value will be masked
masked_array(data=[2.0, 4.0, --],
mask=[False, False, True],
fill_value=1e+20)
>>> 2 * np.ones(3) * ccd_masked.data # ignores the mask
array([2., 4., 6.])
You can force conversion to a numpy array with:
>>> np.asarray(ccd_masked)
array([1, 2, 3])
>>> np.ma.array(ccd_masked.data, mask=ccd_masked.mask)
masked_array(data=[1, 2, --],
mask=[False, False, True],
fill_value=999999)
A method for converting a CCDData object to a FITS HDU list
is also available. It converts the metadata to a FITS header:
>>> hdulist = ccd_masked.to_hdu()
You can also write directly to a FITS file:
>>> ccd_masked.write('my_image.fits')
Masks and Flags¶
Although it is not required when a CCDData image is created,
you can also specify a mask and/or flags.
A mask is a boolean array the same size as the data in which a value of
True indicates that a particular pixel should be masked (i.e., not be
included in arithmetic operations or aggregation).
Flags are one or more additional arrays (of any type) whose shape matches the
shape of the data. One particularly useful type of flag is a bit planes; for
more details about bit planes and the functions astropy provides for
converting them to binary masks, see Utility Functions for Handling Bit Masks and Mask Arrays. For more details
on setting flags, see NDData.
WCS¶
The wcs attribute of a CCDData object can be set two ways.
If the
CCDDataobject is created from a FITS file that has WCS keywords in the header, thewcsattribute is set to aWCSobject using the information in the FITS header.The WCS can also be provided when the
CCDDataobject is constructed with thewcsargument.
Either way, the wcs attribute is kept up to date if the
CCDData image is trimmed.
PSF¶
The psf attributes of a CCDData object can be set two ways.
If the FITS file has an image HDU extension matching the appropriate name (defaulted to
"PSFIMAGE"), thepsfattribute is loaded from that image HDU.The PSF can also be provided when the
CCDDataobject is constructed with thepsfargument.
The psf attribute should be a normalized image representing the PSF at the center of the CCDData, sized appropriately for the data; users are responsible for managing and interpreting it in context.
For more on normalizing a PSF image, see Normalization.
The psf attribute is set to None in the output of an arithmetic operation, no matter the inputs. A warning message is emitted if either of the input images contain a non-None PSF; users are responsible for determining the appropriate thing to do in that context.
Uncertainty¶
You can set the uncertainty directly, either by creating a
StdDevUncertainty object first:
>>> rng = np.random.default_rng()
>>> data = rng.normal(size=(10, 10), loc=1.0, scale=0.1)
>>> ccd = CCDData(data, unit="electron")
>>> from astropy.nddata.nduncertainty import StdDevUncertainty
>>> uncertainty = 0.1 * ccd.data # can be any array whose shape matches the data
>>> my_uncertainty = StdDevUncertainty(uncertainty)
>>> ccd.uncertainty = my_uncertainty
Or by providing a ndarray with the same shape as the data:
>>> ccd.uncertainty = 0.1 * ccd.data
INFO: array provided for uncertainty; assuming it is a StdDevUncertainty. [...]
In this case, the uncertainty is assumed to be
StdDevUncertainty.
Two other uncertainty classes are available for which error propagation is
also supported: VarianceUncertainty and
InverseVariance. Using one of these three uncertainties is
required to enable error propagation in CCDData.
If you want access to the underlying uncertainty, use its .array attribute:
>>> ccd.uncertainty.array
array(...)
Arithmetic with Images¶
Methods are provided to perform arithmetic operations with a
CCDData image and a number, an astropy
Quantity (a number with units), or another
CCDData image.
Using these methods propagates errors correctly (if the errors are
uncorrelated), takes care of any necessary unit conversions, and applies masks
appropriately. Note that the metadata of the result is not set if the
operation is between two CCDData objects.
>>> result = ccd.multiply(0.2 * u.adu)
>>> uncertainty_ratio = result.uncertainty.array[0, 0]/ccd.uncertainty.array[0, 0]
>>> round(uncertainty_ratio, 5)
0.2
>>> result.unit
Unit("adu electron")
Note
The affiliated package ccdproc provides functions for many common data reduction operations. Those functions try to construct a sensible header for the result and provide a mechanism for logging the action of the function in the header.
The arithmetic operators *, /, +, and - are not overridden.
Note
If two images have different WCS values, the wcs on the first
CCDData object will be used for the resultant object.