Skip to content

Commit 2a63e7d

Browse files
authored
Merge pull request #128 from ojustino/poly-trace
Introducing polynomial tracing
2 parents 67b6b8b + 02231cf commit 2a63e7d

12 files changed

+537
-432
lines changed

CHANGES.rst

+8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@
44
New Features
55
^^^^^^^^^^^^
66

7+
- The new FitTrace class (see "API Changes" below) introduces the ability to
8+
take a polynomial trace of an image [#128]
9+
710
API Changes
811
^^^^^^^^^^^
912

13+
- Renamed KosmosTrace as FitTrace, a conglomerate class for traces that are fit
14+
to images instead of predetermined [#128]
15+
- The default number of bins for FitTrace is now its associated image's number
16+
of dispersion pixels instead of 20. Its default peak_method is now 'max'. [#128]
17+
1018
Bug Fixes
1119
^^^^^^^^^
1220

docs/extraction_quickstart.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ the remaining steps of the extraction process. Supported trace types include:
1616

1717
* `~specreduce.tracing.ArrayTrace`
1818
* `~specreduce.tracing.FlatTrace`
19-
* `~specreduce.tracing.KosmosTrace`
19+
* `~specreduce.tracing.FitTrace`
2020

2121

2222
Each of these trace classes takes the 2D spectral image as input, as well as additional information
@@ -47,17 +47,17 @@ or, equivalently::
4747
bg = specreduce.tracing.Background.one_sided(image, 15, separation=5, width=2)
4848

4949

50-
The background image can be accessed via `~specreduce.background.Background.bkg_image` and the
50+
The background image can be accessed via `~specreduce.background.Background.bkg_image` and the
5151
background-subtracted image via `~specreduce.background.Background.sub_image` (or ``image - bg``).
5252

53-
The background and trace steps can be done iteratively, to refine an automated trace using the
53+
The background and trace steps can be done iteratively, to refine an automated trace using the
5454
background-subtracted image as input.
5555

5656
Extraction
5757
----------
5858

5959
The `specreduce.extract` module extracts a 1D spectrum from an input 2D spectrum (likely a
60-
background-extracted spectrum from the previous step) and a defined window, using one of the
60+
background-extracted spectrum from the previous step) and a defined window, using one of the
6161
implemented methods:
6262

6363
* `~specreduce.extract.BoxcarExtract`

licenses/KOSMOS_LICENSE

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# NOTE: This license applies only to code used in the KosmosTrace class.
1+
# NOTE: This license applies only to code used in part of the FitTrace class.
22

33
MIT License
44

notebook_sandbox/compare_extractions.ipynb

+6-6
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
},
2323
{
2424
"cell_type": "code",
25-
"execution_count": 1,
25+
"execution_count": null,
2626
"id": "fc741345-720e-4189-9748-b3bb98d2d693",
2727
"metadata": {},
2828
"outputs": [],
@@ -94,8 +94,8 @@
9494
"metadata": {},
9595
"outputs": [],
9696
"source": [
97-
"index_arr = np.tile(np.arange(nrows), (ncols, 1))\n",
98-
"index_arr.T"
97+
"index_arr = np.broadcast_to(np.arange(nrows)[:, np.newaxis], (nrows, ncols))\n",
98+
"index_arr"
9999
]
100100
},
101101
{
@@ -105,7 +105,7 @@
105105
"metadata": {},
106106
"outputs": [],
107107
"source": [
108-
"img = col_model(index_arr.T) + noise"
108+
"img = col_model(index_arr) + noise"
109109
]
110110
},
111111
{
@@ -214,7 +214,7 @@
214214
"img_obj = CCDData(img, uncertainty=var_obj, mask=mask, unit=u.DN)\n",
215215
"\n",
216216
"hrn2 = HorneExtract(img_obj, trace)\n",
217-
"hrn2_result1d_whole = hrn()"
217+
"hrn2_result1d_whole = hrn2()"
218218
]
219219
},
220220
{
@@ -244,7 +244,7 @@
244244
"metadata": {},
245245
"source": [
246246
"## Compare results\n",
247-
"The whole-image extractions come out as expected, with the Horne-extracted 1D spectrum showing a noticeably better signal-to-noise ratio than its boxcar equivalent."
247+
"The whole-image extractions come out as expected, with the Horne-extracted 1D spectrum showing a noticeably better signal-to-noise ratio than its windowless boxcar equivalent."
248248
]
249249
},
250250
{

notebook_sandbox/horne_extract/optimal_extract_VLT.ipynb

+8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
"# Optimal/Horne extraction exploration"
99
]
1010
},
11+
{
12+
"cell_type": "markdown",
13+
"id": "5b9dc060-5262-463c-ab9b-5790dcf3e9e7",
14+
"metadata": {},
15+
"source": [
16+
"<p style=\"font-size:125%; background-color:#ce1141;\"><b><i>Note:</i> This is an experimental notebook created for an older version of <tt>specreduce</tt>. To learn the package's current best practices, please visit our other notebooks.</b></p>"
17+
]
18+
},
1119
{
1220
"cell_type": "markdown",
1321
"id": "fc5ad51c-fc94-4dfc-8750-3e58b6224278",

notebook_sandbox/jwst_boxcar/boxcar_extraction.ipynb

+16-26
Large diffs are not rendered by default.

notebook_sandbox/jwst_boxcar/jwst_boxcar_algorithm.ipynb

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@
77
"# Spectral extraction tests (JDAT-1855)"
88
]
99
},
10+
{
11+
"cell_type": "markdown",
12+
"metadata": {},
13+
"source": [
14+
"<p style=\"font-size:125%; background-color:#ce1141;\"><b><i>Note:</i> This is an experimental notebook created for an older version of <tt>specreduce</tt>. To learn the package's current best practices, please visit our other notebooks.</b></p>"
15+
]
16+
},
1017
{
1118
"cell_type": "markdown",
1219
"metadata": {},

notebook_sandbox/jwst_boxcar/tracing_options.ipynb

-334
This file was deleted.

notebook_sandbox/tracing_options.ipynb

+381
Large diffs are not rendered by default.

specreduce/background.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def two_sided(cls, image, trace_object, separation, **kwargs):
145145
146146
Example: ::
147147
148-
trace = KosmosTrace(image, guess=trace_pos)
148+
trace = FitTrace(image, guess=trace_pos)
149149
bg = Background.two_sided(image, trace, bkg_sep, width=bkg_width)
150150
151151
Parameters
@@ -178,7 +178,7 @@ def one_sided(cls, image, trace_object, separation, **kwargs):
178178
179179
Example: ::
180180
181-
trace = KosmosTrace(image, guess=trace_pos)
181+
trace = FitTrace(image, guess=trace_pos)
182182
bg = Background.one_sided(image, trace, bkg_sep, width=bkg_width)
183183
184184
Parameters

specreduce/tests/test_tracing.py

+30-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from astropy.modeling import models
55
from specreduce.utils.synth_data import make_2dspec_image
6-
from specreduce.tracing import Trace, FlatTrace, ArrayTrace, KosmosTrace
6+
from specreduce.tracing import Trace, FlatTrace, ArrayTrace, FitTrace
77

88
IM = make_2dspec_image()
99

@@ -66,8 +66,9 @@ def test_array_trace():
6666
assert t_short.shape[0] == IM.shape[1]
6767

6868

69-
# test KOSMOS trace algorithm
70-
def test_kosmos_trace():
69+
# test fitted traces
70+
@pytest.mark.filterwarnings("ignore:Model is linear in parameters")
71+
def test_fit_trace():
7172
# create image (process adapted from compare_extractions.ipynb)
7273
np.random.seed(7)
7374
nrows = 200
@@ -82,7 +83,7 @@ def test_kosmos_trace():
8283
img = col_model(index_arr.T) + noise
8384

8485
# calculate trace on normal image
85-
t = KosmosTrace(img)
86+
t = FitTrace(img, bins=20)
8687

8788
# test shifting
8889
shift_up = int(-img.shape[0]/4)
@@ -96,17 +97,20 @@ def test_kosmos_trace():
9697
t.shift(shift_out)
9798
assert t.trace.mask.all(), 'invalid values not masked'
9899

99-
# test peak_method options
100-
tg = KosmosTrace(img, peak_method='gaussian')
101-
tc = KosmosTrace(img, peak_method='centroid')
102-
tm = KosmosTrace(img, peak_method='max')
100+
# test peak_method and trace_model options
101+
tg = FitTrace(img, bins=20,
102+
peak_method='gaussian', trace_model=models.Legendre1D(3))
103+
tc = FitTrace(img, bins=20,
104+
peak_method='centroid', trace_model=models.Chebyshev1D(2))
105+
tm = FitTrace(img, bins=20,
106+
peak_method='max', trace_model=models.Spline1D(degree=3))
103107
# traces should all be close to 100
104108
# (values may need to be updated on changes to seed, noise, etc.)
105109
assert np.max(abs(tg.trace-100)) < sigma_pix
106110
assert np.max(abs(tc.trace-100)) < 3 * sigma_pix
107111
assert np.max(abs(tm.trace-100)) < 6 * sigma_pix
108112
with pytest.raises(ValueError):
109-
t = KosmosTrace(img, peak_method='invalid')
113+
t = FitTrace(img, peak_method='invalid')
110114

111115
# create same-shaped variations of image with invalid values
112116
img_all_nans = np.tile(np.nan, (nrows, ncols))
@@ -116,25 +120,37 @@ def test_kosmos_trace():
116120
img_win_nans = img.copy()
117121
img_win_nans[guess - window:guess + window] = np.nan
118122

119-
# ensure a low bin number is rejected
123+
# ensure float bin values trigger a warning but no issues otherwise
124+
with pytest.warns(UserWarning, match='TRACE: Converting bins to int'):
125+
FitTrace(img, bins=20., trace_model=models.Polynomial1D(2))
126+
127+
# ensure non-equipped models are rejected
128+
with pytest.raises(ValueError, match=r'trace_model must be one of*'):
129+
FitTrace(img, trace_model=models.Hermite1D(3))
130+
131+
# ensure a bin number below 4 is rejected
120132
with pytest.raises(ValueError, match='bins must be >= 4'):
121-
KosmosTrace(img, bins=3)
133+
FitTrace(img, bins=3)
134+
135+
# ensure a bin number below degree of trace model is rejected
136+
with pytest.raises(ValueError, match='bins must be > '):
137+
FitTrace(img, bins=4, trace_model=models.Chebyshev1D(5))
122138

123139
# ensure number of bins greater than number of dispersion pixels is rejected
124140
with pytest.raises(ValueError, match=r'bins must be <*'):
125-
KosmosTrace(img, bins=ncols)
141+
FitTrace(img, bins=ncols + 1)
126142

127143
# error on trace of otherwise valid image with all-nan window around guess
128144
try:
129-
KosmosTrace(img_win_nans, guess=guess, window=window)
145+
FitTrace(img_win_nans, guess=guess, window=window)
130146
except ValueError as e:
131147
print(f"All-NaN window error message: {e}")
132148
else:
133149
raise RuntimeError('Trace was erroneously calculated on all-NaN window')
134150

135151
# error on trace of all-nan image
136152
try:
137-
KosmosTrace(img_all_nans)
153+
FitTrace(img_all_nans)
138154
except ValueError as e:
139155
print(f"All-NaN image error message: {e}")
140156
else:

0 commit comments

Comments
 (0)