A multiwavelength FITS explorer for black hole astrophysics β from ROSAT to JWST, all in one Streamlit app.
Load NASA-archive FITS files from Chandra, XMM-Newton, NuSTAR, ROSAT, JWST (NIRSpec/NIRCam), WISE, 2MASS, VLA, and DSS. Render them correctly. Build calibrated multi-band SEDs. Bin X-ray event lists. Fit X-ray spectra. Compute LombβScargle periodograms and Vaughan+2003 fractional rms variability. Reproduce Little Red Dot diagnostics. All on a laptop.
Quick start Β· Features Β· Targets Β· Phase 2: Little Red Dots Β· FITS pitfalls catalog Β· Roadmap Β· Cite
A short list of the specific tasks this app is built around:
- Load a Chandra / XMM / NuSTAR event file and turn it into an image with the right energy cut. β X-ray event list-to-image binning.
- View a JWST NIRSpec spectrum with redshifted line markers. β Phase 2 NIRSpec tab (planned).
- Build a multi-band Spectral Energy Distribution for an AGN with consistent units across radio β X-ray. β Unit-safe SED builder.
- Look up whether WISE colors are AB or Vega, and how the Stern / Donley cuts are defined. β PITFALLS #6,
physics/infrared.py. - Reproduce the L_X / L_UV plot for a Little Red Dot. β Phase 2 diagnostics (planned).
- Investigate zero-count gaps in an X-ray light curve. β GTI handling (planned M4).
- See the asinh stretch, the Donley wedge, the Eddington luminosity, the LombβScargle periodogram, and the Vaughan+2003 F_var in one place with primary-source citations. β That's the whole app.
Search keywords (for discoverability): Chandra event file Python viewer, JWST NIRSpec FITS Streamlit, multiwavelength SED AGN, OGIP PHA spectrum power law, WCS overlay matplotlib origin lower, asinh stretch astronomical image, ROSAT All-Sky Survey cutout, VLA FIRST 1.4 GHz, WISE Stern Donley AGN color cut, Eddington luminosity calculator, ShakuraβSunyaev disk temperature, fractional rms variability Vaughan 2003, LombβScargle X-ray light curve, Little Red Dots JWST, L_X/L_UV Lusso Risaliti 2016, Reines & Volonteri 2015, hardness ratio AGN, Compton-thick Seyfert 2 NGC 1068, M87 jet, Cyg X-1 black hole binary, astroquery SkyView HEASARC, photutils aperture photometry, specutils Spectrum1D, FITS pitfalls.
# 1. Clone and set up an environment (Python 3.11+)
git clone https://github.com/ysSemanticSystems/BlackHoleResearch.git
cd BlackHoleResearch
python3.11 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 2. Download the curated multi-survey dataset (~50β200 MB from NASA SkyView)
python scripts/download_data.py
# 3. Launch the Streamlit app
streamlit run app.pyBrowser opens at http://localhost:8501.
Want to add Chandra event files? See Adding more data below for HEASARC, MAST, and IRSA recipes.
The right way: World Coordinate System overlay in J2000 sexagesimal, origin='lower' (FITS convention, not NumPy's default), and an asinh stretch so the dynamic range of an AGN core plus a galaxy halo plus an extended jet doesn't collapse to a black square. Supports linear, sqrt, log, asinh, and DS9-style zscale. Perceptually uniform colormaps only β no jet.
Backed by astropy.visualization.ImageNormalize and WCSAxes. The render path explicitly handles partial-or-missing WCS (a frequent issue in cutouts from older missions; see PITFALLS #3).
Chandra ACIS, XMM-Newton EPIC, NuSTAR FPM and NICER files are photon tables, not images. This app reads the EVENTS extension, picks the right X/Y/ENERGY(or PI) columns per mission, and bins them into a 2D image with an energy cut you control (soft <2 keV vs hard >2 keV by default β useful for spotting Compton-thick obscuration). The pitfalls of mistaking PI channels for eV (XMM/NuSTAR) are guarded against in code; see PITFALLS #12.
Loads OGIP-format *.pha / *.pi files, auto-detects COUNTS vs RATE columns, plots in log-log channel space with Poisson errors, and fits a power law N(E) β E^(βΞ) over a channel range you select. Honest disclaimer: without RMF/ARF response files this is a channel-space slope, not a calibrated photon index β for publication-grade Ξ, plug into Sherpa or XSPEC (planned Phase 2 hook). The classification table maps Ξ ranges to AGN populations (Ricci+2017 BAT survey).
The money plot for any accreting black hole. Takes points across nine decades of frequency (1.4 GHz to 50 keV), unit-checked via astropy.units (Jy β erg/s/cmΒ²/Hz β Ξ½F_Ξ½), color-coded by band, with an optional Elvis+1994 quasar template overlay. Resolves the radio jet synchrotron, the mid-IR torus bump, the optical/UV disk thermal continuum, and the X-ray corona power law on a single log-log axis. See blackhole/sed.py.
Bins arbitrary event lists into uniformly sampled light curves, computes a LombβScargle periodogram via astropy.timeseries.LombScargle (the right tool for unevenly sampled, gap-filled data β see VanderPlas 2018), and computes the fractional rms variability amplitude with proper Vaughan+2003 Eq. B2 error bars. AGN typically show 5β30 % F_var on hour-day timescales; X-ray binaries can hit 50 % during bright hard states.
β οΈ GTI handling is Phase 2 (M4). Light curves over real Chandra/XMM/NuSTAR observations have Good Time Interval gaps that currently render as zero-count bins; full GTI masking is planned. See PITFALLS #10.
Self-contained reference implementations:
| Module | Formulas | Primary source |
|---|---|---|
accretion.py |
Eddington luminosity, accretion rate αΉ = L/(Ξ·cΒ²), ShakuraβSunyaev T(r) | Eddington 1926; Shakura & Sunyaev 1973 |
spectral_xray.py |
Hardness ratio HR = (HβS)/(H+S) with Poisson error, photon-index classification | Ricci+2017 ApJS 233, 17 |
infrared.py |
Blackbody Ξ½B_Ξ½(T), Stern+2012 single-color cut, Donley+2012 four-band wedge | Stern+2012, Donley+2012 |
variability.py |
Excess variance, fractional rms F_var with Vaughan+2003 errors | Vaughan+2003 MNRAS 345, 1271 |
Every formula has its primary source in the docstring; enforcement of citation discipline is in .cursor/rules/01-documentation-standards.mdc.
docs/PITFALLS.md is a 14-entry reference covering the recurring issues that come up when working with archival FITS files:
- Event-list-as-image confusion
- Linear stretch destroying dynamic range
- WCS silently missing or partial
origin='lower'and flipped-image debugging- Cross-band unit confusion (Jy / mag / keV / Hz)
- WISE Vega-vs-AB photometry
- PHA spectra requiring RMF/ARF
- Big-endian byte order in raw FITS arrays
- Memmap invalidation after
with fits.open()exits - GTI artifacts in light curves
- Coordinate frame mismatches (ICRS / FK5 / Galactic)
- PI-channel vs eV energy filters
- Mission time systems (Chandra/XMM TT vs NuSTAR UTC)
- Modified Julian Date conventions (the half-day offset)
Each entry has a symptom, a cause, and a concrete code defense with citations.
| Target | Why it's a milestone | Mass | Distance |
|---|---|---|---|
| NGC 1068 | The archetypal Seyfert 2 / Compton-thick AGN. Antonucci & Miller 1985's polarized broad-line discovery here founded AGN unification. The mid-IR torus dominates everything < 30 Β΅m. | M_BH β 1.7 Γ 10β· Mβ (maser, Lodato+2003) | ~14 Mpc |
| M87 | The first directly imaged event horizon (EHT Collaboration 2019). A low-luminosity AGN with an extended optical/radio jet observed since Curtis 1918. | M_BH = 6.5 Γ 10βΉ Mβ (EHT 2019) | ~16.8 Mpc |
| Cyg X-1 | The first widely accepted stellar-mass black hole (Webster & Murdin 1972; Bolton 1972). Bright, variable, observed by every major X-ray mission since 1964. | M_BH β 21 Mβ (Miller-Jones+2021) | ~2.2 kpc |
Each is downloaded as a stack of multi-band cutouts from NASA SkyView; see fits_data/MANIFEST.json for the SHA-stamped, provenance-tracked file list.
The post-2023 JWST surprise. Little Red Dots (LRDs) are compact, high-redshift sources with broad permitted lines implying accreting 10βΆβ10βΈ Mβ black holes β but they show no detected X-ray emission (even in deep Chandra stacks; Akins+2025, Yue+2024) and no detected mid-IR torus. They appear to violate AGN unification in both bands at once.
Phase 2 (see PHASE2_PLAN.md) adds:
- LRD catalog with peer-reviewed redshifts and M_BH (Greene+2024, Maiolino+2024, Harikane+2023, Akins+2025, Wang+2024).
- JWST NIRSpec / NIRCam ingestion via
astroquery.mast. - Diagnostics β exact reproductions of:
- Ξ±_ox + L_X / L_UV vs Lusso & Risaliti 2016 mean relation;
- Balmer break detector (Setton+2024, Wang+2024 definitions);
- Broad HΞ± β M_BH via Reines & Volonteri 2015 calibration;
- Donley+2012 WISE wedge with LRDs overlaid as the outliers they are.
The Phase 2 goal is a reproducible, citation-tracked LRD pipeline that emits calibrated values with uncertainties, and that anyone can run on a laptop.
| Layer | Library | What we use it for |
|---|---|---|
| FITS I/O | astropy.io.fits | All file loading, header parsing, BinTable handling |
| Units | astropy.units | End-to-end unit safety across SED bands |
| WCS | astropy.wcs | World coordinate overlays on every image |
| Stretches | astropy.visualization | Asinh, log, sqrt, ZScale + percentile clipping |
| Cosmology | astropy.cosmology (Phase 2) | Planck18 luminosity distances for LRDs |
| Periodograms | astropy.timeseries | LombβScargle on unevenly sampled data |
| Archives | astroquery | SkyView, HEASARC, MAST, IRSA queries |
| Photometry | photutils (Phase 2) | Aperture photometry + background annuli |
| Spectra | specutils (Phase 2) | NIRSpec _x1d Spectrum1D handling |
| Sky regions | regions | DS9 region serialization |
| UI | Streamlit | Tabbed multi-target browser |
If you're an astropy user, you can read or extend this codebase fluently.
BlackHoleResearch/
βββ app.py # Streamlit UI β presentation layer only
βββ PHASE2_PLAN.md # Milestone roadmap with binary exit criteria
βββ AGENTS.md # Contributor & AI-agent guide
βββ CITATION.cff # Machine-readable citation metadata
βββ codemeta.json # Research software metadata (codemeta v2.0)
βββ .zenodo.json # Zenodo upload metadata
βββ README.md
βββ LICENSE # MIT
βββ requirements.txt
βββ .cursor/rules/ # Persistent AI-agent guidance (10 focused rules)
βββ .github/ # (Phase 2 M0) CI workflows
βββ fits_data/
β βββ MANIFEST.json # SHA-256, provenance, fetched-at per file
β βββ *.fits # Multi-survey cutouts (gitignored)
βββ scripts/
β βββ download_data.py # SkyView cross-mission cutout fetcher
βββ blackhole/
β βββ io.py # FITS load/inspect/event-list binning
β βββ wcs_plot.py # Image rendering w/ WCS + stretches
β βββ spectra.py # OGIP PHA loader + power-law fit
β βββ sed.py # Multi-band SED assembly (units-safe)
β βββ lightcurves.py # Binning + Lomb-Scargle
β βββ physics/
β βββ accretion.py # Eddington, αΉ, ShakuraβSunyaev
β βββ spectral_xray.py # Hardness ratio, photon-index classification
β βββ infrared.py # Blackbody, Stern+Donley WISE cuts
β βββ variability.py # F_var, excess variance
βββ docs/
βββ PITFALLS.md # 14-entry FITS failure-mode catalog
βββ adr/ # Architecture Decision Records
from astroquery.heasarc import Heasarc
import astropy.units as u
h = Heasarc()
obs = h.query_object("NGC 1068", catalog="chanmaster", radius=5 * u.arcmin)
print(obs[["obsid", "exposure", "ra", "dec"]])
h.download_data(obs[:1], host="heasarc", location="fits_data/")evt2.fits event files drop directly into the X-ray Events tab.
from astroquery.mast import Observations
obs = Observations.query_object("CEERS-415", radius=0.05)
products = Observations.get_product_list(obs[:1])
Observations.download_products(products, download_dir="fits_data/")NIRSpec _x1d.fits files will land in the Phase 2 NIRSpec viewer tab.
from astroquery.ipac.irsa import Irsa
result = Irsa.query_region("NGC 1068", catalog="allwise_p3as_psd",
radius="0d0m30s")Conventions are defined in AGENTS.md and enforced in CI.
Before opening a PR:
- Read
AGENTS.mdfor the project's prime directives and PR checklist. - Pick a milestone from
PHASE2_PLAN.mdand tick its binary exit criteria in the PR description. - Run the local pre-merge checks (
ruff check,mypy --strict blackhole/,pytest -q).
The persistent AI/contributor rules live in .cursor/rules/:
00-project-context.mdcβ repo identity (always loaded)01-documentation-standards.mdcβ module/function docstring shape, citation requirements02-scientific-honesty.mdcβ units, uncertainty, no invented values03-python-style.mdcβ typing, dataclasses, error hierarchy04-fits-handling.mdcβ FITS dos/donts mapped to PITFALLS05-testing-discipline.mdcβ coverage targets, fixture conventions06-ui-patterns.mdcβ Streamlit-as-presentation invariant07-reproducibility.mdcβ provenance, manifest, caching, cosmology08-adr.mdcβ when and how to write Architecture Decision Records09-commit-and-pr.mdcβ commit message + PR template (always loaded)
If you use this software in a publication, please cite via the Cite this repository widget on the GitHub sidebar (powered by CITATION.cff), or as:
@software{blackholeresearch_2026,
author = {ysSemanticSystems},
title = {{BlackHoleResearch: A Multiwavelength FITS Explorer for
Black Hole Astrophysics}},
year = {2026},
url = {https://github.com/ysSemanticSystems/BlackHoleResearch},
version = {0.1.0},
license = {MIT}
}A Zenodo DOI is planned at the Phase 2 v0.2.0 release (PHASE2_PLAN.md Β§M11). Please cite the primary-source papers for any physics formula you use (citations are inline in module docstrings and aggregated in PHASE2_PLAN.md Β§11).
If this isn't the right tool for your task, one of these probably is:
- SAOImage DS9 β the canonical interactive FITS image viewer.
- CIAO + Sherpa β Chandra data reduction and forward-folded spectral fitting. The right tool for calibrated Ξ measurements.
- XSPEC β the X-ray spectral fitting standard, with response-file forward-folding.
- SAS β the XMM-Newton reduction package.
- JWST pipeline β official JWST data reduction (we consume its outputs, we don't replace it).
- Stingray β Python X-ray timing analysis at depth (more advanced than our M4 light-curve module).
- aplpy β beautiful publication-quality WCS plots.
- Astropy tutorials β the canonical learning resource.
- NED Β· SIMBAD Β· ADS β the meta-archives every astronomer lives in.
This project's niche is multiwavelength survey-data exploration with calibration-aware SEDs and LRD diagnostics, with an emphasis on teaching the pitfalls.
- FITS Standard v4.0 β IAU FITS Working Group, 2018.
- OGIP/92-007 β X-ray spectrum FITS conventions.
- OGIP/93-003 β Type II PHA file structure.
- WCS Paper II (Calabretta & Greisen 2002) β World Coordinate System.
- VOTable β IVOA tabular data.
- CFF 1.2.0 β Citation File Format.
- CodeMeta 2.0 β Research Software Metadata.
- SPDX MIT β license identification.
- Keep a Changelog + SemVer 2.0 β version & changelog conventions.
This software is built on the work of the astropy project (Astropy Collaboration 2013, 2018, 2022) and the astroquery project (Ginsburg et al. 2019, AJ 157, 98).
Data is provided by:
- NASA SkyView (HEASARC, Goddard Space Flight Center).
- HEASARC β High Energy Astrophysics Science Archive Research Center.
- MAST β Mikulski Archive for Space Telescopes (STScI).
- IRSA β NASA/IPAC Infrared Science Archive.
- VizieR β CDS, Strasbourg.
All NASA-archive data redistributed here is U.S. public domain.
Hosted on GitHub: https://github.com/ysSemanticSystems/BlackHoleResearch
If this is useful to you, a β helps others find it.