A simple tool to manipulate and visualize UV/optical/NIR spectra for astronomical research.
Online documentation is hosted on Read the Docs: https://specbox.readthedocs.io/en/latest/index.html
@software{fu_2026_18642758,
author = {Fu, Yuming},
title = {specbox: a simple tool to manipulate and visualize UV/optical/NIR spectra for astronomical research},
month = feb,
year = 2026,
publisher = {Zenodo},
version = {v1.0.0},
doi = {10.5281/zenodo.18642758},
url = {https://doi.org/10.5281/zenodo.18642758}
}GPLv3. See LICENSE.
numpyscipyastropypyqtgraphPySide6specutilsmatplotlibpandaspyarroworfastparquet(optional, for reading parquet spectra tables)requestspillow(PIL)astroquery
It is recommended to set up an isolated environment before installing (choose either option A or B):
# Option A: Python venv
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip# Option B: conda
conda create -n specbox python=3.13 -y
conda activate specbox
python -m pip install --upgrade pipInstall the stable release from PyPI (recommended):
python -m pip install specboxTo install a pre-release/development version from source:
git clone https://github.com/rudolffu/specbox.git
cd specbox
python -m pip install .specbox installs three CLIs:
specbox-viewer: launch the enhanced viewerspecbox-coadd: coadd Euclid BGS+RGS chunksspecbox-euclid-parquet: convert raw single-arm Euclid combined FITS to parquetspecbox-pcf: run template PCF redshift and writeZ_TEMP
# Viewer (history auto-loads when output CSV already exists)
specbox-viewer --spectra your_spectra.fits --spec-class euclid
# Viewer without image panel or cutout downloads
specbox-viewer --spectra your_spectra.fits --spec-class euclid --no-images
# Coadd paired Euclid arms (default: EXTNAME intersection)
specbox-coadd --rgs-file rgs_chunk.fits --bgs-file bgs_chunk.fits --output-prefix coadd/out_chunk_001
# Convert raw single-arm Euclid FITS to parquet
specbox-euclid-parquet --fits rgs_chunk.fits --output-prefix parquet/rgs_chunk_001
# PCF default: Type 1 only
specbox-pcf --fits coadd/out_chunk_001.fits
# PCF with Type 1 + Type 2 (ragn_na, internally limited to 0 < z < 3)
specbox-pcf --fits coadd/out_chunk_001.fits --enable-type2
# PCF with ragn_dr1 only (mapped to type1)
specbox-pcf --fits coadd/out_chunk_001.fits --ragn-dr1-onlyThe main classes and functions of specbox are:
SpecLAMOSTandSpecSDSS: classes to read and manipulate spectra from the LAMOST and SDSS surveys, respectively.SpecIRAF: class to read and manipulate spectra from the IRAF format.SpecEuclid1d: reader for Euclid combined 1D spectra, withMASK/good_masksupport and optionalgood_pixels_only=True.SpecEuclid1dDual: paired Euclid reader for BGS+RGS with overlap scaling and merged/coadd-ready outputs.SpecEuclidCoaddRow: reader for dataframe/parquet rows containing coadded spectra arrays.SpecPandasRow: generic reader for "table-of-spectra" files readable by pandas (parquet/csv/feather/...), where each row stores arrays (e.g. wavelength/flux/ivar).SpecSparcl: SPARCL parquet/table reader (e.g., for filesparcl_spectra.parquet). Common metadata columns includedata_release,targetid, and (optional)euclid_object_idfor Euclid overlay.
PGSpecPlot: class to plot spectra in apyqtgraphplot.PGSpecPlotApp: class to create apyqtgraphplot with aQApplicationinstance.PGSpecPlotThread: class to create apyqtgraphplot in a thread.
from specbox import SpecLAMOST
spec = SpecLAMOST('input_file.fits')
spec.plot()
# Smooth the spectrum
spec.smooth(5, 3, inplace=False)from specbox.basemodule import SpecSparcl
# ext is a 1-based row index (ext=1 -> first row)
sp1 = SpecSparcl("sparcl_spectra.parquet", ext=1)
sp1.plot()from specbox.basemodule import SpecEuclid1d
sp = SpecEuclid1d("sz_ragn_dr1_rgs_chunk_001_part001.parquet", ext=1)
sp.plot()specbox-viewer \
--spectra coadd/sz_ragn_dr1_coadd_chunk_001_part001.parquet \
--spec-class euclid-coaddAdd --no-images when cutouts are unavailable or should be skipped entirely.
from specbox import SpecLAMOST
from specbox.qtmodule import PGSpecPlotThread
from glob import glob
basepath = 'lamost_spec/fits_files/'
flist = glob(basepath+'*fits.gz')
flist.sort()
flist = flist[0:60]
a = PGSpecPlotThread(speclist=flist, SpecClass=SpecLAMOST, output_file='vi_output_test60.csv')
a.run()from specbox.basemodule import SpecSparcl
from specbox.qtmodule import PGSpecPlotThreadEnhanced
viewer = PGSpecPlotThreadEnhanced(
spectra="sparcl_spectra.parquet",
SpecClass=SpecSparcl,
# Optional: overlay Euclid spectrum when the parquet has `euclid_object_id`
# and the Euclid combined FITS uses that ID as `EXTNAME`.
euclid_fits="COMBINED_EUCLID_SPECS.fits",
output_file="sparcl_vi_results.csv",
z_max=6.0,
load_history=True,
)
viewer.run()Notes:
- Results CSV includes
targetidanddata_release(when available from the input table). - The enhanced viewer has a
Save PNGbutton that writes screenshots to./saved_pngs/.
