Skip to content

extract_spectrum_boxcar

Trace (easyspec) + pure-numpy aperture extraction on ctx.image.

Category Extraction (2-D to 1-D)
Backend easyspec - wraps the EasySpec reduction library (optional extra reduction)
Version 3.1.0
Reads ctx.image (an ImageFrame)
Writes spectrum, metrics.boxcar_columns_without_sky, metrics.trace_center_row

Tracing uses easyspec.tracing (argmax → polynomial). Extraction is a numpy aperture sum over the symmetric window round(y(x)) ± trace_half_width (2·trace_half_width + 1 rows) around the per-column trace position, fully edge-safe (any partial slice outside the detector contributes zero). tophat ⇒ standard boxcar; gaussian ⇒ profile-weighted (Gaussian fit on the mean column profile). easyspec is imported lazily inside run(). v3.0.0 (audit A9): up to v2 the aperture was [int(y) − hw, int(y) + hw) — int() truncates and the half-open window holds 2·hw rows, so the aperture sat 0.5 to 1.5 px below the trace depending on its fractional part and the captured fraction rippled with it (Gaussian profile σ = 1.5 px, hw = 3: 0.947 at trace row 20.0, 0.928 at 20.3, 0.910 at 20.5, 0.860 at 20.9). The rounded, symmetric window captures 0.983 / 0.980 / 0.976 / 0.982 on the same profile (ripple 0.7 % instead of 8.7 %). The sky region is likewise round(median_trace) ± shift_y_pixels inclusive, so each flanking window is exactly shift_y_pixels − trace_half_width rows high on the median row. Numerical impact on a well-sampled trace: one more row in the sum (+1 × sky per column when shift_y_pixels = 0) and up to +9 % flux where the old window was off-centre. Note: the gaussian mode here is profile-weighted but NOT variance-weighted and does NOT propagate per-pixel uncertainty or reject cosmics during extraction. For the full Horne 1986 estimator (inverse-variance weighting, empirical profile, iterative cosmic rejection, uncertainty propagation) see extract_spectrum_optimal — choose it for faint, read-noise-limited sources or when downstream code needs Spectrum1D.uncertainty. Sky geometry: with shift_y_pixels > 0 the two flanking windows run from the aperture edge (round(trace) ± trace_half_width) out to round(median_trace) ± shift_y_pixels, so each is shift_y_pixels − trace_half_width rows high on the median row; shift_y_pixels must exceed trace_half_width (refused otherwise). v2.0.0: the per-column sky is the mean of the NON-empty windows — v1 averaged a 0 in for an empty window, so a tilted trace (which empties one window over many columns because the bounds follow the median trace) had its sky halved there (audit case: 162/400 columns at half sky). Columns where both windows are empty get sky = 0 and are counted in the additive metric boxcar_columns_without_sky. The pixel axis is 0-based (numpy.arange(npix)). v3.1.0: trace_method='fixed' extracts the symmetric window trace_center_row ± trace_half_width on every column without any tracing (IRAF apall without aptrace, the constant-trace case of the same aperture sum), so extended sources filling the slit are extracted on a predictable band of rows; the default argmax mode and the moments / multi modes are byte-identical to 3.0.0. The fixed mode imports neither easyspec nor matplotlib, so it runs without the reduction extra ; its Spectrum1D meta carries trace_method and trace_center_row, and the metrics gain trace_center_row.

Parameters

Parameter Default Required Description
trace_method 'argmax' - 'argmax', 'moments' or 'multi' (easyspec tracing), or 'fixed': no tracing, the aperture is centred on trace_center_row for every column.
trace_center_row None - Detector row the aperture is centred on in 'fixed' mode (0-based); null means the middle row, n_rows // 2. Ignored by the tracing modes.
trace_poly_order 2 - Polynomial order of the trace fit.
trace_y_pixel_range 15 - Half-window (rows) for the trace search.
trace_peak_height 100.0 - Minimum peak height when locating the trace.
trace_peak_distance 50 - Minimum separation between traces (multi mode).
trace_half_width 7 - Aperture half-width (rows) for both trace and extraction: the aperture is the symmetric window round(y(x)) ± trace_half_width, i.e. 2·trace_half_width + 1 rows.
extraction_weights 'tophat' - 'tophat' (boxcar sum) or 'gaussian' (Horne-weighted).
shift_y_pixels 0 - Half-height (rows) of the sky region centred on the median trace row (round(median_trace) ± shift_y_pixels inclusive): each flanking sky window spans from the aperture edge (round(trace) ± trace_half_width) out to that region's edge, i.e. shift_y_pixels - trace_half_width rows on the median row. Must exceed trace_half_width; 0 disables background subtraction.

Use it

from spectro_kernel import run_algorithm

output = run_algorithm("extract_spectrum_boxcar", ctx, {
    "trace_method": "argmax",
    "trace_center_row": None,
    "trace_poly_order": 2,
    "trace_y_pixel_range": 15,
    "trace_peak_height": 100.0,
    "trace_peak_distance": 50,
    "trace_half_width": 7,
    "extraction_weights": "tophat",
    "shift_y_pixels": 0
})

The CLI loads a single 1-D spectrum with --input; this algorithm needs ctx.image (an ImageFrame). Run it from Python or as a step of a pipeline preset.

{
  "tool": "extract_spectrum_boxcar",
  "arguments": {
    "session_id": "<session_id>",
    "params": {
      "trace_method": "argmax",
      "trace_center_row": null,
      "trace_poly_order": 2,
      "trace_y_pixel_range": 15,
      "trace_peak_height": 100.0,
      "trace_peak_distance": 50,
      "trace_half_width": 7,
      "extraction_weights": "tophat",
      "shift_y_pixels": 0
    }
  }
}

Every algorithm is an MCP tool of the same name; describe_algorithm returns this page's metadata as JSON.

References

  • Horne 1986, PASP 98, 609 — optimal aperture extraction (tophat is the standard unweighted variant).
  • Tody 1986, Proc. SPIE 627, 733 — IRAF apall / aptrace heritage.
  • easyspec.extraction.extraction.tracing — argmax / moments trace fit.