Skip to main content

Chita 🐆 — a fast cat(alog) maker

Catalogs from Hierarchical, Image-calibrated, Tuning-free Analysis. Pronounced like cheetah.

Chita is an ultra-fast, multi-scale source extractor for large astronomical images (Roman, Euclid, Rubin era). One run finds point sources, compact and extended galaxies, and low-surface-brightness (LSB) objects. You don't run it twice with "hot" and "cold" settings, and you don't tune it per field.

  • Self-calibrating thresholds. The noise of every filtered map is measured, so 5 sigma means 5 sigma on every image, including drizzled or resampled coadds with correlated noise.
  • Multi-scale in one pass. A PSF-matched detection is combined with a Gaussian pyramid of coarser significance maps. Coarse-scale light that finer scales don't explain becomes a new (LSB) source; envelopes of known sources are attached to them.
  • Statistical deblending. A component tree (dendrogram) with noise-unit tests replaces SExtractor's 32 fixed levels plus a global contrast. Leftover pixels are assigned by a deterministic watershed.
  • Built-in purity estimate. The same detection runs on the inverted image at every scale.
  • Fast. Rust, multi-threaded at every stage, with O(N) or O(N log N) kernels. Results are identical for any thread count.

The documentation has the guides, the API and the technical notes: the design describes the algorithm, and the review covers the existing codes it learns from. python scripts/build_site.py api and html build it, with the website, into site/build/.

Install

pip install chita

This installs the Python package and the chita command, ready to run on Linux, macOS and Windows with Python 3.9 or newer. Nothing is compiled.

To install the latest code from GitHub instead, which compiles it, first install Rust:

pip install git+https://github.com/lmytime/chita

Command line

chita image.fits                          # -> image.cat.fits (FITS binary table)
chita image.fits -o cat.csv --seg seg.fits --bkg bkg.fits --rms rms.fits
chita image.fits --weight wht.fits --weight-type weight --mask bad.fits --gain 2.0

chita --help lists all options. The defaults are meant to be left alone:

option default meaning
--thresh 5.0 detection: peak significance, in measured sigma of the detection image
--analysis-thresh 2.0 footprint (isophote) significance
--fwhm estimated PSF FWHM (pixels)
--back-size 64 background mesh (pixels)
--contrast 0.005 deblending: minimum flux fraction of a split, applied only above the detection level
--levels auto number of coarse scales (0 disables multi-scale)
--subsources off search large objects for compact sources and clumps inside them (flag 512; experimental with one band)
-j all cores threads

While it runs, chita prints each stage as it finishes, with what it found and how long it took. Under them, a live line shows the running stage: a spinner, a progress bar for the long stages (reading, deblending, coarse scales, measurement) and the elapsed time. A summary closes the run:

  🐆 chita v0.0.2 · fast multi-scale source extraction
     bench/out/real/primer_f444w_sci.fits · 10 threads

  ✓ Read image + weight  8192 × 8192 · 537 MB           299 ms
  ✓ Background (masked)  sky σ 2.82e-3                  398 ms
  ✓ Significance map     correlated noise ×2.50         536 ms
  ✓ Deblending           9,793 sources                  685 ms
  ✓ Coarse scales        +68 sources, 9 envelopes       259 ms
  ⠹ Measurement          ━━━━━━━━━╸──── 6,992/9,861     227 ms

  ╭──────────────────────────────────────────────────────────╮
  │ 9,861 sources in 3.73 s                                  │
  │ 9,793 at the PSF scale · 68 on coarse scales             │
  │ spurious estimate 82 (0.8%), from the inverted image     │
  ╰──────────────────────────────────────────────────────────╯

(Some stage lines are left out here.) When stderr is not a terminal, such as a pipe or a log file, the same lines are printed as the stages finish, without colour or the live line. --color never (or NO_COLOR=1) turns the colour off, and -q prints only errors.

It reads any BITPIX, BSCALE/BZERO/BLANK, and primary or IMAGE-extension FITS. For tile-compressed (.fz) images, use chita.extract_file in Python (it reads them through astropy).

Python

import chita

res = chita.extract(image)                    # 2-D numpy array (any dtype)
res = chita.extract(image, weight=wht, mask=bad, gain=2.0, threads=8)
res = chita.extract_file("image.fits", hdu=1)  # via astropy; RA/Dec from its header
res = chita.extract(image, header=hdr)          # RA/Dec from a FITS header or astropy WCS

cat = res.catalog          # numpy structured array (as_table=True -> astropy Table)
seg = res.segmentation     # 0 = sky, else source id
res.background, res.rms    # full-resolution maps
res.info                   # FWHM used, noise correlation, spurious estimate, timings

Several bands

Images of several bands on one pixel grid are detected jointly and then measured band by band with the same apertures. Detection is not diluted for sources seen in only one or two bands (docs/multiband.md). Inside large objects, compact sources and clumps whose colour differs from the object's are found as sources of their own (flag 512; subsources=False turns this off):

mb = chita.MultiBand(width, height)
for name, sci, err in bands:                    # in wavelength order
    mb.add_band(name, sci, err, weight_type="rms", fwhm=psf_fwhm[name])
det = mb.detect()                               # catalog, segmentation, detection map
det.catalog["det_window"]                       # e.g. "F356W-F444W": the bands that found it
det.info["n_sub"]                               # compact sources and clumps found inside large objects

phot = chita.forced_photometry(sci, det.segmentation, det.catalog, err,
                                 aper_radii=[3.3, 5.0], kron_factors=(2.5, 1.2), fwhm=psf_fwhm[name])

MultiBand(width, height, header=hdr) gives the catalog RA/Dec.

Images on other pixel grids

Images from other telescopes (HST, for example) can be measured at the detection's positions. Each is converted to nJy, resampled onto the detection grid and aligned to it:

scale = chita.flux_scale(hst_hdr)           # nJy per pixel unit: MJy/sr, e-/s + PHOTFNU, nanomaggies, zeropoints
sci, err = chita.resample(hst * scale, hst_hdr, det_hdr, error=hst_err * scale)  # Lanczos-3, flux conserving
off = chita.measure_offset(sci, err, det.catalog, det.segmentation)              # on compact sources
fixed_hdr = chita.shift_header(hst_hdr, off["dx"], off["dy"], det_hdr)           # then resample again
stars, sseg = chita.psf.find_stars(sci, err, near=detected_xy)                     # stellar locus, real sources only
psf, frac = chita.psf.build_epsf(sci, np.c_[stars["x_win"], stars["y_win"]], segmentation=sseg, labels=stars["id"])
kernel = chita.psf.matching_kernel(psf, reference_psf)

The catalogue script does all of this with --other BAND=SCI:WEIGHT (docs/multiband.md).

Seeing-limited images (DECam, HSC, ...) are fitted instead, in their own pixels, with each detection's light in a sharp band as its template (chita.templatefit). The kernel is the image's PSF from listed stars (Gaia), or a Moffat profile fitted on the brightest sources:

from chita import templatefit as tf

kernel, fwhm, beta = tf.fit_kernel(hr, seg, cat, hr_wcs, lr, lr_err, lr_wcs, hr_scale=0.03)   # without stars
a = tf.templates(hr, seg, cat, kernel, hr_wcs, lr_wcs, lr.shape)   # sparse: pixels x sources
flux, err, cov_index, model = tf.solve(a, lr, 1 / lr_err**2)        # all fluxes at once

In the catalogue script this is --lowres BAND=SCI:WEIGHT --lowres-stars gaia.csv. On Legacy Surveys DECam images of RXCJ2211 it agrees with the Tractor catalogue to 1–4% in g and r; i and z come out about 10% higher, not yet understood (docs/multiband.md).

scripts/multiband_catalog.py builds a complete catalog this way:

  • native and PSF-matched photometry;
  • aperture corrections to the total flux from empirical PSFs;
  • random-aperture errors;
  • nJy fluxes;
  • quality columns;
  • images on other pixel grids, such as HST (--other);
  • seeing-limited images, fitted with templates (--lowres).

Photometric redshifts

chita.photoz fits templates at every redshift of a grid, with EAZY's conventions and files (filters, template lists, template error, IGM), but exactly, in parallel and about ten times faster per core. On EAZY's own inputs it reproduces EAZY's χ²(z) to 10⁻⁷ (docs/photoz.md). Its defaults go further: NIRCam's in-flight throughputs (JDox v7), a template list of its own (Hainline et al.'s, with redshift ranges, and a β = −3.2 template), a cap on the luminosity, calibrated p(z), and star and little-red-dot fits next to the galaxies'. On 14,000 NIRSpec redshifts they cut the outliers from 21.6% to 17.7% with eight NIRCam bands:

python scripts/photoz_catalog.py catalog_phot.fits --eazy-dir /path/to/eazy/data --mw-ebv 0.0851
python scripts/highz_candidates.py catalog_phot.fits --zmin 7      # classed z > 7 candidates

Visual inspection

scripts/vi_figures.py draws one figure per source: the SED with the redshift fit (AB magnitudes on the right axis), p(z) and χ²(z), the source's numbers, and north-up stamps in every band with an RGB composite and the segmentation (guide):

python scripts/vi_figures.py catalog_phot.fits --eazy-dir /path/to/eazy/data --workers 8

Catalogue columns

Coordinates are 0-based with pixel centres at integers (numpy convention). Add 1 to compare with SExtractor/FITS conventions.

column meaning
x, y isophotal barycentre
x_win, y_win windowed (iterative Gaussian) centroid, as SExtractor's XWIN
ra, dec; ra_win, dec_win sky coordinates (degrees) of the barycentre and the windowed centroid, from the image's TAN or TAN-SIP WCS; NaN without one
x_peak, y_peak brightest pixel
x2, y2, xy, a, b, theta second moments, RMS semi-axes, position angle (rad, CCW from +x)
npix, flux_iso, flux_iso_err segment area and flux
kron_radius, flux_auto, flux_auto_err Kron radius (units of a,b) and Kron-aperture (2.5, min 3.5) flux; neighbours replaced by mirror pixels
flux_aper, flux_aper_err circular apertures (default radii 1 and 2 x FWHM), exact pixel overlap
flux_radius, fwhm half-light radius; FWHM from the half-maximum area
peak, det_sig, snr peak value, peak significance at the detection scale, AUTO S/N
bkg local background (plus the subtracted halo level for ON_HALO objects)
scale detection scale: 0 = PSF scale, k = pyramid level (~2^k px)
parent, nblend footprint id and number of sources deblended from it
host id of the brighter object on whose light (halo or body) this one sits, for ON_HALO objects; else 0
flags 1 blended, 2 edge, 4 masked pixels, 8 saturated, 16 AUTO aperture truncated, 32 windowed centroid failed, 64 neighbours in AUTO aperture, 128 grown with a coarse-scale envelope, 256 on a brighter object's halo or body (host; its light there was subtracted), 512 sub-source: a compact source or clump found inside its host (use circular apertures)

Benchmarks

bench/simulate.py makes GalSim images with known truth: stars, Sérsic galaxies (some with star-forming knots), LSB dwarfs, background structure, and white or correlated noise. bench/validate.py compares Chita with SEP, SExtractor and photutils using one-to-one matching and threshold sweeps. bench/speed.py measures throughput.

python bench/simulate.py --size 4096 --fwhm 2.5 --out bench/out/sim_ground
python bench/validate.py bench/out/sim_ground --sweep --photutils
python bench/speed.py bench/out/sim_ground.fits

Results are in docs/results.md.

On real images, bench/real_eval.py injects sources into a mosaic and recovers them. It covers blank sky and the wings of bright objects, and uses the inverted image as a purity proxy. bench/real_report.py turns its output into tables and a trade-off figure. docs/real_images.md covers JWST/NIRCam mosaics of Abell 2744 and PRIMER-COSMOS: the failure modes they exposed, the fixes, and the comparison with the other codes.

Repository layout

crates/chita-core   Rust library (background, filters, labeling, deblending,
                    measurement, pipeline, FITS I/O)
crates/chita-cli    `chita` command
crates/chita-py     Python bindings (PyO3) + `chita` package + tests
bench/              simulations, validation and speed benchmarks
scripts/            multi-band catalogues, photometric redshifts, VI figures, site build
docs/               guides, reference and technical notes (the documentation's source)
site/               the website's home page and the documentation's style
pyproject.toml      Python packaging (maturin)
.github/workflows/  tests on every push; packages and releases on version tags

Development

Building from a clone needs Rust ≥ 1.75 and maturin:

maturin develop --release        # the Python package and `chita`, into the active environment
cargo build --release            # the command alone: target/release/chita
cargo test --release             # Rust tests
python -m pytest crates/chita-py/tests

environment.yml creates a conda environment with the benchmark codes as well (SEP, photutils, GalSim, SExtractor):

conda env create -f environment.yml && conda activate chita

Releasing

  1. Set the new version in Cargo.toml ([workspace.package]) and commit.
  2. Tag and push: git tag v0.2.0 && git push origin v0.2.0.

The Release workflow then builds and tests the packages for every platform, publishes them to PyPI and creates the GitHub release. PyPI accepts them because the project trusts this repository's release.yml workflow in the pypi environment (trusted publishing); no token is stored.

Building inside a conda shell

Some conda setups export CFLAGS for a different architecture (for example -march=core2 from an Intel anaconda on Apple Silicon). Chita itself has no C code. If you add C-based dependencies, build with env -u CFLAGS -u CPPFLAGS cargo build --release.

Metadata

Release files for chita 0.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chita 0.0.2
File Size Uploaded Provenance Actions
chita-0.0.2.tar.gz 1.8 MB With provenance Details for chita-0.0.2.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for chita 0.0.2
File Actions
chita-0.0.2-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details for chita-0.0.2-cp39-abi3-win_amd64.whl
chita-0.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details for chita-0.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
chita-0.0.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details for chita-0.0.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
chita-0.0.2-cp39-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 10.12+ universal2 (ARM64, x86-64), macOS 10.12+ x86-64, macOS 11.0+ ARM64 Details for chita-0.0.2-cp39-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl

Total release size: 13.5 MB

Release files / chita-0.0.2.tar.gz

Download URL chita-0.0.2.tar.gz
Size 1.8 MB
Tags Source
SHA-256 checksum
How to use checksums
0114f8ec485f32d74c4a43b8cfe1b31c8871999d97233018742068a27e07a0ce
BLAKE2b-256 checksum
How to use checksums
b993f83b19e3af6a0df26f4a9bbcec1697f3093f279fcda084ac16868942f4bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / chita-0.0.2-cp39-abi3-win_amd64.whl

Download URL chita-0.0.2-cp39-abi3-win_amd64.whl
Size 2.7 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
434b562be24d722bebf76b774febd596d76047f9a3971706f96526a3cc46daa4
BLAKE2b-256 checksum
How to use checksums
523e2b6a5003d4e152791ee173df14ad21b56941531494975f0d8b4e4e35e214
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / chita-0.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL chita-0.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 2.7 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
2f0832311916345d153c6da858d5487700f8d73aeb2c2f1965de7c60a2672c8b
BLAKE2b-256 checksum
How to use checksums
1a90faa16c9148e8ab26b76a79cdead498994f6d90f997db3caf6534f9ee21d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / chita-0.0.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL chita-0.0.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 2.7 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
fe38e22f750e5b1f8507e7eb7d75518f9775adab38a777af2bb09bc190b4db1b
BLAKE2b-256 checksum
How to use checksums
64dcaa6cdce73fa6d63f0abdb082b1adf20b686ef543381d906055f495b29a63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Release files / chita-0.0.2-cp39-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl

Download URL chita-0.0.2-cp39-abi3-macosx_10_12_universal2.macosx_10_12_x86_64.macosx_11_0_arm64.whl
Size 3.6 MB
Tags CPython 3.9 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
086505d5ccf967a38f4fc933966a0edc99972bfe5fc794b8ecb58ae59b75f7d9
BLAKE2b-256 checksum
How to use checksums
b5242b3a2d9bfb2590a055b65282dd9b6934b20e11126c08ad855697e4e8bc18
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

Security for chita 0.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 5 files in this release have been uploaded with provenance metadata.

Select from 5 files

Attestation for chita-0.0.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 31, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.0.2 This release

5 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page