Skip to content

PhangsTeam/astro-HexMaps

Repository files navigation


HexMaps

Hexagonal-grid Multi-data Analysis and Processing Software
Explore the docs »

View Demo · Report Bug · Request Feature

Contributors Forks Stargazers Issues MIT License


About the Project

HexMaps screenshot

HexMaps is a Python package for homogenizing and analysing multi-wavelength astronomical datasets on hexagonal grids. It is ideally suited for combining a heterogeneous set of 2D maps and 3D spectral cubes observed at different angular resolutions and pixel scales into a single, science-ready table for sightline-by-sightline analysis.

Given a set of input data, HexMaps:

  1. Regrids all maps and cubes onto a common hexagonal sampling grid at a user-specified angular resolution, convolving each dataset to a common beam.
  2. Processes each spectral cube: builds an S/N mask from a reference line, then computes moment maps (integrated intensity, mean velocity, line width, peak temperature, rms, equivalent width) and shuffled spectra for every line.
  3. Writes FITS output: PPV-native moment maps, optionally convolved cubes, and 2D band images — all on the same pixel grid as the overlay cube.

The primary deliverable is an Astropy .ecsv table with one row per hexagonal sightline, containing all spectra, moment maps, and 2D map values side by side. This makes line-ratio analysis, radial profile extraction, and spectral stacking straightforward with standard Python tools.

HexMaps is the successor to PyStructure (PhangsTeam), refactored into a pip-installable package with a clean CLI, an INI-style single configuration file, and a modular stage architecture.

(back to top)


Getting Started

Prerequisites

HexMaps requires Python ≥ 3.10. All Python dependencies are installed automatically by pip:

astropy  numpy  pandas  scipy  matplotlib
reproject  radio_beam  spectral_cube  scikit-image

Installation

# From PyPI (once published)
pip install astro-hexmaps

# From GitHub — latest version
pip install git+https://github.com/PhangsTeam/astro-HexMaps.git

# Editable / development install
git clone https://github.com/PhangsTeam/astro-HexMaps.git
cd astro-HexMaps
pip install -e ".[dev]"

(back to top)


Usage

1 — Initialise a working directory

# Creates config.txt, keys/, and run_hexmaps.py in the current folder
hexmaps --init

# Or target a specific directory
hexmaps --init --workdir ~/my_survey
cd ~/my_survey

This copies template configuration files into your working directory. The installed package is never modified.

2 — Download the example dataset (optional)

To try the pipeline immediately with real data, download the bundled NGC 5194 example dataset (~46 MB):

hexmaps --download-example --workdir ~/my_survey

This fetches the input FITS files (CO(2–1) cube, CO(1–0) cube, SPIRE 250 µm map and associated uncertainty files) into ~/my_survey/data/. The bundled config.txt is already configured to use these files, so you can run the pipeline straight away after downloading. Use --force to re-download existing files.

3 — Edit your configuration

File What to configure How often
config.txt data directory, source list, overlay cube, maps/cubes, target resolution, masking, output flags every run
keys/target_definitions.txt sky coordinates, distance, inclination per target only when adding new targets
keys/hfs_lines.txt (optional) Hyperfine structure line definitions rarely

config.txt replaces the PyStructure.conf file of the old PyStructure.

Migrating from PyStructure? Use the conversion scripts:

python conversion_from_pystructure/config_conversion.py PyStructure.conf config.txt
python conversion_from_pystructure/target_definitions_conversion.py geometry.txt keys/target_definitions.txt
python conversion_from_pystructure/hfs_lines_conversion.py hfs_lines.txt keys/hfs_lines.txt

4 — Run

# Default: regrid + products (writes .ecsv database)
hexmaps --conf config.txt

# All stages including FITS output
hexmaps --conf config.txt --stages all

# Single source
hexmaps --conf config.txt --targets ngc5194

# Also write a log file
hexmaps --conf config.txt --log_file run.log

Or from Python:

import hexmaps as hm

handler = hm.PipelineHandler(conf_path="config.txt")
handler.run_all()                                      # regrid + products
handler.run_stages(["regrid", "products", "fits"])     # include FITS output
handler.run_stages(["fits"], targets=["ngc5194"])      # re-run one stage only

For more examples, please refer to the Documentation.

(back to top)


Repository Layout

astro-HexMaps/                       ← git repository root (pip install this)
├── hexmaps/                         ← installable package
│   ├── handler_keys.py              reads & validates config and key files
│   ├── handler_sources.py           source geometry lookups
│   ├── handler_pipeline.py          PipelineHandler: stage orchestration
│   ├── stage_regrid.py              hex grid + convolution + sampling → .ecsv
│   ├── stage_products.py            spectral masking, moments, shuffled spectra
│   ├── stage_fits.py                FITS moment maps / cubes / band images
│   ├── utils_fits.py                FITS/WCS helpers (convolution, reprojection)
│   ├── utils_table.py               table I/O, spectral shuffle, moments
│   ├── logger.py                    centralised stage-labelled logger
│   ├── init_workdir.py              --init scaffolding
│   ├── download_example.py          --download-example data fetcher
│   ├── cli.py                       hexmaps console-script entry point
│   ├── test_hexmaps.py              unit and integration tests
│   └── templates/                   template files copied by --init
│       ├── config.txt
│       ├── run_hexmaps.py
│       └── keys/
│           ├── target_definitions.txt
│           └── hfs_lines.txt
├── config.txt                       ← example / template config file
├── keys/
│   ├── target_definitions.txt       ← source geometry table (NGC 5194 example)
│   └── hfs_lines.txt                ← hyperfine structure definitions
├── analysis/
│   ├── hexmaps_analysis.py          HexMapsAnalysis class: quicklook plots
│   └── hexmaps_example.ipynb        example analysis notebook
├── conversion_from_pystructure/     ← migration scripts from old PyStructure
│   ├── config_conversion.py
│   ├── target_definitions_conversion.py
│   └── hfs_lines_conversion.py
├── data/                            ← example FITS input (NGC 5194)
├── docs/                            ← Sphinx / Read the Docs source
├── images/                          ← README images (logo, screenshot)
├── run_hexmaps.py                   ← example run script
└── pyproject.toml

Pipeline Stages

The pipeline runs three stages always in this order:

Stage Module Default Description
regrid stage_regrid.py Generate the hexagonal sampling grid; convolve and sample all maps & cubes onto it; write the .ecsv database
products stage_products.py Build the S/N mask; compute moment maps (mom0/1/2, Tpeak, rms, EW) and shuffled spectra
fits stage_fits.py optional Compute PPV-native moment maps on the convolved cubes; write FITS images

The default run (hexmaps --conf config.txt) executes regrid + products only. Add --stages all to also run the fits stage.


Reading the Output

from hexmaps.utils_table import load_hexmaps
import matplotlib.pyplot as plt

table = load_hexmaps("output/ngc5194_hexmaps_27p0as_2025_01_01.ecsv")

plt.figure(figsize=(5, 5))
plt.scatter(table["ra_deg"], table["dec_deg"],
            c=table["MOM0_12CO21"], marker="h", s=60, cmap="inferno")
plt.gca().invert_xaxis()
plt.xlabel("R.A. [deg]"); plt.ylabel("Dec. [deg]")
plt.show()

For richer quicklook plots use the HexMapsAnalysis class:

import sys; sys.path.append("analysis/")
from hexmaps_analysis import HexMapsAnalysis

db = HexMapsAnalysis("output/ngc5194_hexmaps_27p0as_2025_01_01.ecsv")
db.quickplot_map("12CO21")
db.quickplot_spectrum("12CO21")

# Recover provenance information embedded at run time
print(db.get_config())               # recover config.txt used for this run
print(db.get_log())                  # recover the full pipeline log
hdr = db.get_input_header("12CO21")  # recover raw FITS header of input cube
print(db.list_input_headers())       # list all embedded headers

(back to top)


Roadmap

  • PyPI release
  • Expanded documentation and tutorials
  • Additional analysis utilities in hexmaps_analysis.py
  • Various feature updates (e.g. "island-method" masking, chunking for large datasets)

See the open issues for a full list of proposed features and known issues.

(back to top)


Contributing

Contributions are greatly appreciated! If you have a suggestion that would make this better, please fork the repository and create a pull request. You can also open an issue with the tag "enhancement".

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

(back to top)


License

Distributed under the MIT License — see LICENSE for details.

(back to top)


Contact

Dr. Jakob den Brok — jadenbrok@mpia.de

Dr. Lukas Neumann — lukas.neumann@eso.org

Project Link: https://github.com/PhangsTeam/astro-HexMaps

(back to top)


Acknowledgements

HexMaps builds on the original PyStructure IDL scripts developed within the PHANGS collaboration. The routines have been updated, improved, and fully rewritten in Python.

The code has been employed in several peer-reviewed publications including den Brok et al. (2021, 2022, 2023, 2025), Eibensteiner et al. (2022, 2023), Neumann et al. (2023), Stuber et al. (2025), and others. See the documentation for the full list.

(back to top)

About

No description, website, or topics provided.

Resources

License

Stars

5 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors