Skip to content

Commit

Permalink
support generic traces for backgrounds
Browse files Browse the repository at this point in the history
* with factory classmethods for one_sided and two_sided which handle the separation from an input spectrum trace
  • Loading branch information
kecnry committed Mar 17, 2022
1 parent 565081f commit ba994c3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 46 deletions.
20 changes: 16 additions & 4 deletions notebook_sandbox/jwst_boxcar/boxcar_extraction.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -307,12 +307,17 @@
"metadata": {},
"outputs": [],
"source": [
"# extract the background around an estimated Trace\n",
"# extract the background using custom individual traces\n",
"trace = FlatTrace(image, ext_center)\n",
"bg = Background(image, trace, separation=bkg_sep, width=bkg_width)\n",
"bg = Background(image, [trace-bkg_sep, trace+bkg_sep], width=bkg_width)\n",
"\n",
"# for the case of a FlatTrace, the central value can be passed directly instead\n",
"bg = Background(image, ext_center, separation=bkg_sep, width=bkg_width)"
"bg = Background.two_sided(image, trace, bkg_sep, width=bkg_width)\n",
"# or in the place of any trace, an int/float can be passed which resolves to a FlatTrace\n",
"bg = Background.two_sided(image, ext_center, bkg_sep, width=bkg_width)\n",
"\n",
"# or for single sided:\n",
"# bg = Background.one_sided(image, trace, bkg_sep, width=bkg_width)\n",
"# bg = Background.one_sided(image, trace, -bkg_sep, width=bkg_width)"
]
},
{
Expand Down Expand Up @@ -590,6 +595,13 @@
"[Top of Page](#top)\n",
"<img style=\"float: right;\" src=\"https://raw.githubusercontent.com/spacetelescope/notebooks/master/assets/stsci_pri_combo_mark_horizonal_white_bkgd.png\" alt=\"Space Telescope Logo\" width=\"200px\"/> "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
Expand Down
122 changes: 80 additions & 42 deletions specreduce/background.py
Original file line number Diff line number Diff line change
@@ -1,99 +1,137 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst

from dataclasses import dataclass
from dataclasses import dataclass, field

import numpy as np
from astropy.nddata import CCDData

from specreduce.core import SpecreduceOperation
from specreduce.extract import _ap_weight_image
from specreduce.tracing import Trace, FlatTrace

__all__ = ['Background']


@dataclass
class Background(SpecreduceOperation):
class Background:
"""
Determine the background from an image for subtraction
Parameters
----------
image : nddata-compatible image
image with 2-D spectral image data
trace_object : Trace
trace object
traces : List
list of trace objects (or integers to define FlatTraces) to
extract the background
width : float
width of extraction aperture in pixels
disp_axis : int
dispersion axis
crossdisp_axis : int
cross-dispersion axis
Returns
-------
spec : `~specutils.Spectrum1D`
The extracted 1d spectrum expressed in DN and pixel units
"""
# required so numpy won't call __rsub__ on individual elements
# https://stackoverflow.com/a/58409215
__array_ufunc__ = None

image: CCDData
trace_object: Trace
separation: float = 5
traces: list = field(default_factory=list)
width: float = 5
disp_axis: int = 1
crossdisp_axis: int = 0

def __post_init__(self):
"""
Extract the 1D spectrum using the boxcar method.
Determine the background from an image for subtraction.
Parameters
----------
image : nddata-compatible image
image with 2-D spectral image data
trace_object : Trace or int
trace object or an integer to use a FloatTrace
separation: float
separation between trace and extraction apertures on each
side of the trace
traces : List
list of trace objects (or integers to define FlatTraces) to
extract the background
width : float
width of each background aperture in pixels
disp_axis : int
dispersion axis
crossdisp_axis : int
cross-dispersion axis
"""
if isinstance(self.trace_object, (int, float)):
self.trace_object = FlatTrace(self.image, self.trace_object)

# TODO: this check can be removed if/when implemented as a check in FlatTrace
if isinstance(self.trace_object, FlatTrace):
if self.trace_object.trace_pos < 1:
raise ValueError('trace_object.trace_pos must be >= 1')

if self.width >= 2 * self.separation:
raise ValueError("width must be < 2*separation to avoid spectral region")

bkg_wimage = _ap_weight_image(
self.trace_object-self.separation,
self.width,
self.disp_axis,
self.crossdisp_axis,
self.image.shape)

bkg_wimage += _ap_weight_image(
self.trace_object+self.separation,
self.width,
self.disp_axis,
self.crossdisp_axis,
self.image.shape)
def _to_trace(trace):
if not isinstance(trace, Trace):
trace = FlatTrace(self.image, trace)

# TODO: this check can be removed if/when implemented as a check in FlatTrace
if isinstance(trace, FlatTrace):
if trace.trace_pos < 1:
raise ValueError('trace_object.trace_pos must be >= 1')
return trace

bkg_wimage = np.zeros_like(self.image, dtype=np.float64)
for trace in self.traces:
trace = _to_trace(trace)
bkg_wimage += _ap_weight_image(trace,
self.width,
self.disp_axis,
self.crossdisp_axis,
self.image.shape)

if np.any(bkg_wimage > 1):
raise ValueError("background regions overlapped")

self.bkg_wimage = bkg_wimage
self.bkg_array = np.average(self.image, weights=self.bkg_wimage, axis=0)

@classmethod
def two_sided(cls, image, trace_object, separation, **kwargs):
"""
Determine the background from an image for subtraction centered around
an input trace.
Parameters
----------
image : nddata-compatible image
image with 2-D spectral image data
trace_object: Trace
estimated trace of the spectrum to center the background traces
separation: float
separation from ``trace_object`` for the background regions
width : float
width of each background aperture in pixels
disp_axis : int
dispersion axis
crossdisp_axis : int
cross-dispersion axis
"""
kwargs['traces'] = [trace_object-separation, trace_object+separation]
return cls(image=image, **kwargs)

@classmethod
def one_sided(cls, image, trace_object, separation, **kwargs):
"""
Determine the background from an image for subtraction above
or below an input trace.
Parameters
----------
image : nddata-compatible image
image with 2-D spectral image data
trace_object: Trace
estimated trace of the spectrum to center the background traces
separation: float
separation from ``trace_object`` for the background, positive will be
above the trace, negative below.
width : float
width of each background aperture in pixels
disp_axis : int
dispersion axis
crossdisp_axis : int
cross-dispersion axis
"""
kwargs['traces'] = [trace_object+separation]
return cls(image=image, **kwargs)

def bkg_image(self, image=None):
"""
Expose the background tiled to the dimension of ``image``.
Expand Down

0 comments on commit ba994c3

Please sign in to comment.