Source code for sofia_redux.instruments.forcast.background

# Licensed under a 3-clause BSD style license - see LICENSE.rst

import statistics

import numpy as np

from sofia_redux.toolkit.utilities.fits import hdinsert, href, kref

__all__ = ['background', 'mode']


[docs] def mode(data): """ Return the most common data point from discrete or nominal data If there is not exactly one most common value, the minimum value (of the most common values) will be returned. Parameters ---------- data : numpy.ndarray Returns ------- The most common value Raises ------ ValueError If data is empty """ d = np.array(data).ravel() result = min(statistics.multimode(d)) return result
[docs] def background(data, section, header=None, stat=None, mask=None): """ Calculate the background of the image Takes median or mode of good pixels in selected region Parameters ---------- data : numpy.ndarray (nimage, ncol, nrow) section : tuple of (int or float) or list of (int or float) Data section to use. Should have the format (X0, Y0, XDIM, YDIM) where X0, Y0 is the center of the section and XDIM, YDIM is the dimension of the section. header : astropy.io.fits.header.Header, optional Input header array to be updated with NLINSLEV (containing the background levels) and HISTORY keyworks stat : str, optional Statistic to use to calculate the background level ('median' or 'mode') mask : numpy.ndarray, optional (col, row) Illumination mask to indicate regions of the image to use in calculating the image (True = good) Returns ------- numpy.ndarray (nimage) containing background levels for each input frame """ if len(section) != 4: raise ValueError( "section should have the format (x0, y0, xdim, ydim)") ndim = len(data.shape) if ndim not in [2, 3]: return box_x = section[0] - section[2] / 2.0, section[0] + section[2] / 2.0 box_y = section[1] - section[3] / 2.0, section[1] + section[3] / 2.0 if ndim == 2: nplanes, (ny, nx) = 1, data.shape else: nplanes, ny, nx = data.shape if not isinstance(mask, np.ndarray): mask = np.full((ny, nx), True) mask = mask.astype(bool) y, x = np.meshgrid(*map(np.arange, mask.shape), indexing='ij') mask *= (x > box_x[0]) & (x < box_x[1]) & (y > box_y[0]) & (y < box_y[1]) if not mask.any(): return func = mode if stat == 'mode' else np.nanmedian if ndim == 2: result = [func(data[mask])] else: result = tuple(map(lambda u: func(data[u, :, :][mask.astype(bool)]), range(nplanes))) if header is not None: nlinslev = ','.join(str(x) for x in result) hdinsert(header, 'NLINSLEV', '[%s]' % nlinslev, comment='Signal level of the background', refkey=kref) history = 'Background: level is (%s) ' % nlinslev history += 'using section defined by NLINSLEV keyword' hdinsert(header, 'HISTORY', history, refkey=href) return np.array(result)