Skip to content

ysSemanticSystems/BlackHoleResearch

Repository files navigation

BlackHoleResearch

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.

Python 3.11+ License: MIT astropy Streamlit FITS NASA data Code style: ruff Status: Phase 1, Phase 2 planned

Quick start Β· Features Β· Targets Β· Phase 2: Little Red Dots Β· FITS pitfalls catalog Β· Roadmap Β· Cite


What it does

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.


⚑ Quick start

# 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.py

Browser opens at http://localhost:8501.

Want to add Chandra event files? See Adding more data below for HEASARC, MAST, and IRSA recipes.


πŸ”­ What you can do with this

πŸ–Ό Render any FITS image with WCS, properly

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).

πŸ“‘ X-ray event list-to-image binning

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.

πŸ“ˆ OGIP PHA spectrum loader with descriptive power-law fit

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).

🌌 Multi-band SED builder: radio β†’ mid-IR β†’ optical β†’ X-ray

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.

⏱ Light curve + Lomb–Scargle periodogram + Vaughan+2003 F_var

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.

πŸ”¬ Physics module with citations

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.

πŸ“š A documented catalog of common FITS failure modes

docs/PITFALLS.md is a 14-entry reference covering the recurring issues that come up when working with archival FITS files:

  1. Event-list-as-image confusion
  2. Linear stretch destroying dynamic range
  3. WCS silently missing or partial
  4. origin='lower' and flipped-image debugging
  5. Cross-band unit confusion (Jy / mag / keV / Hz)
  6. WISE Vega-vs-AB photometry
  7. PHA spectra requiring RMF/ARF
  8. Big-endian byte order in raw FITS arrays
  9. Memmap invalidation after with fits.open() exits
  10. GTI artifacts in light curves
  11. Coordinate frame mismatches (ICRS / FK5 / Galactic)
  12. PI-channel vs eV energy filters
  13. Mission time systems (Chandra/XMM TT vs NuSTAR UTC)
  14. Modified Julian Date conventions (the half-day offset)

Each entry has a symptom, a cause, and a concrete code defense with citations.


🎯 The targets and the physics

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.


🌠 Phase 2 β€” JWST Little Red Dots research frontier

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.


🧬 Built on the astropy ecosystem

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.


πŸ“‚ Project structure

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

πŸ›° Adding more data

Chandra / XMM-Newton / NuSTAR (HEASARC)

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.

JWST / HST / TESS (MAST)

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.

Spitzer / WISE / 2MASS (IRSA)

from astroquery.ipac.irsa import Irsa
result = Irsa.query_region("NGC 1068", catalog="allwise_p3as_psd",
                            radius="0d0m30s")

🀝 Contributing

Conventions are defined in AGENTS.md and enforced in CI.

Before opening a PR:

  1. Read AGENTS.md for the project's prime directives and PR checklist.
  2. Pick a milestone from PHASE2_PLAN.md and tick its binary exit criteria in the PR description.
  3. 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 requirements
  • 02-scientific-honesty.mdc β€” units, uncertainty, no invented values
  • 03-python-style.mdc β€” typing, dataclasses, error hierarchy
  • 04-fits-handling.mdc β€” FITS dos/donts mapped to PITFALLS
  • 05-testing-discipline.mdc β€” coverage targets, fixture conventions
  • 06-ui-patterns.mdc β€” Streamlit-as-presentation invariant
  • 07-reproducibility.mdc β€” provenance, manifest, caching, cosmology
  • 08-adr.mdc β€” when and how to write Architecture Decision Records
  • 09-commit-and-pr.mdc β€” commit message + PR template (always loaded)

πŸ“– Citation

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).


🌐 See also

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.


πŸ“‹ Standards adhered to

  • 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.

πŸͺ Acknowledgements

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.

About

Multiwavelength FITS explorer for black hole astrophysics. Loads Chandra, XMM, NuSTAR, ROSAT, JWST, WISE, 2MASS, VLA, DSS. Builds multi-band SEDs, bins X-ray event lists, fits OGIP PHA spectra, computes Lomb-Scargle and F_var. Phase 2: JWST Little Red Dot diagnostics. Built on astropy + Streamlit.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages