Subtract wisp artifacts in JWST NIRCam images with the non-negative matrix factorization (NMF) algorithm
Project description
NMFwisp
NMFwisp subtracts wisps from JWST/NIRCam images using data-driven, detector- and filter-specific templates.
Wisps are scattered-light artifacts in JWST/NIRCam images. They usually appear in the same locations on NIRCam detectors with mild morphological variation between observations. Wisps are a significant source of contamination for objects fainter than 25 AB mag.
The template library is built using the Non-negative Matrix Factorization (NMF) algorithm, leveraging extensive NIRCam data from JADES and other programs. Compared with single-template approaches, the NMF-based method captures exposure-to-exposure wisp morpholigical variation, while retaining sensitivity to the low-surface-brightness structure of the wisps.
Wisp subtraction is intended for Stage 2 of the JWST calibration pipeline. The main user interface is the fit_wisp funciton, which returns the best-fit wisp model and its uncertainty. Templates are distributed with the package in the nmfwisp/templates folder. The developer/ directory contains scripts used to build the template library. The package size is 82 MB including the templates. Typical runtime on one CPU core (Apple M4 Pro) is ~0.4 s per exposure for standard fitting and ~2 s per exposure with iterative 1/f noise correction.
Installation
Install from PyPI:
pip install nmfwisp
Alternatively, development install from source:
git clone https://github.com/zihaowu-astro/NMFwisp.git
cd NMFwisp
pip install -e .
Example
Example Data (Optional): to run the example below, download the sample dataset:
curl -L -O https://github.com/zihaowu-astro/NMFwisp/releases/download/v1.0/example-data.tar.gz
tar -xzf example-data.tar.gz
Direct download link: example-data.tar.gz
from astropy.io import fits
import matplotlib.pyplot as plt
import numpy as np
from nmfwisp import fit_wisp
filter_name = "F150W"
detector_name = "nrcb4"
filename = "./data/jw01286001001_07201_00003_nrcb4_rate.fits"
maskfile = "./data/jw01286001001_07201_00003_nrcb4_cal_bkgsub_tweak_smask-full.fits"
data = fits.open(filename)["SCI"].data
err = fits.open(filename)["ERR"].data
mask = fits.open(maskfile)[0].data
wisp, wisp_e = fit_wisp(
data, err, mask,
detector_name=detector_name,
filter_name=filter_name,
correct_1f=False,
)
Use a custom template path (optional):
wisp, wisp_e = fit_wisp(
data, err, mask,
wisp_path="/path/to/templates",
detector_name=detector_name,
filter_name=filter_name,
correct_1f=False,
)
Visualization:
data0 = np.nan_to_num(data, nan=0.0)
fig, ax = plt.subplots(1, 3, figsize=(10, 4))
vmin, vmax = np.nanpercentile(data, 5), np.nanpercentile(data, 95)
ax[0].imshow(data0, origin="lower", vmin=vmin, vmax=vmax)
ax[0].set_title("Data")
ax[1].imshow(data0 - wisp, origin="lower", vmin=vmin, vmax=vmax)
ax[1].set_title("Data - WISP")
ax[2].imshow(wisp, origin="lower", vmin=0, vmax=np.nanpercentile(wisp, 99))
ax[2].set_title("WISP")
for a in ax:
a.axis("off")
plt.tight_layout()
plt.show()
Wisp Morphology
Citation
If you use this code, please cite this paper:
@ARTICLE{2026arXiv260115958W,
author = {{Wu}, Zihao and {Johnson}, Benjamin D. and {Eisenstein}, Daniel J. and {Cargile}, Phillip and {Hainline}, Kevin and {Hausen}, Ryan and {Rinaldi}, Pierluigi and {Robertson}, Brant E. and {Tacchella}, Sandro and {Williams}, Christina C. and {Willmer}, Christopher N.~A.},
title = "{JWST Advanced Deep Extragalactic Survey (JADES) Data Release 5: Wisp Subtraction with the Non-negative Matrix Factorization Algorithm}",
journal = {arXiv e-prints},
keywords = {Instrumentation and Methods for Astrophysics, Astrophysics of Galaxies},
year = 2026,
month = jan,
eid = {arXiv:2601.15958},
pages = {arXiv:2601.15958},
doi = {10.48550/arXiv.2601.15958},
archivePrefix = {arXiv},
eprint = {2601.15958},
primaryClass = {astro-ph.IM},
adsurl = {https://ui.adsabs.harvard.edu/abs/2026arXiv260115958W},
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
}
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file nmfwisp-1.1.2.tar.gz.
File metadata
- Download URL: nmfwisp-1.1.2.tar.gz
- Upload date:
- Size: 91.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ec5de78f63c18386a2a5a9c58a795ecb3f70501cab04aea1c1564af2733149c
|
|
| MD5 |
0dd5c6c24de1d3945461f993aa7d320b
|
|
| BLAKE2b-256 |
f7465adaff7250440cdd3e2f342d5538090489f2de5ff58b33d99f8f78b707f5
|
Provenance
The following attestation bundles were made for nmfwisp-1.1.2.tar.gz:
Publisher:
publish-to-pypi.yml on zihaowu-astro/NMFwisp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nmfwisp-1.1.2.tar.gz -
Subject digest:
2ec5de78f63c18386a2a5a9c58a795ecb3f70501cab04aea1c1564af2733149c - Sigstore transparency entry: 1174330468
- Sigstore integration time:
-
Permalink:
zihaowu-astro/NMFwisp@bf0c85a291702089509de3652f6791b0ba82eec3 -
Branch / Tag:
refs/tags/v1.1.2 - Owner: https://github.com/zihaowu-astro
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-to-pypi.yml@bf0c85a291702089509de3652f6791b0ba82eec3 -
Trigger Event:
release
-
Statement type: