SkillAgentSearch skills...

Astrometry

Astrometry turns a list of star positions into a pixel-to-sky transformation (WCS)

Install / Use

/learn @neuromorphicsystems/Astrometry
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Astrometry

Astrometry turns a list of star positions into a pixel-to-sky transformation (WCS) by calling C functions from the Astrometry.net library (https://astrometry.net).

Astrometry.net star index files ("series") are automatically downloaded when required.

This package is useful for solving plates from a Python script, comparing star extraction methods, or hosting a simple local version of Astrometry.net with minimal dependencies. See https://github.com/dam90/astrometry for a more complete self-hosting solution.

Unlike Astrometry.net, Astrometry does not include FITS parsing or image pre-processing algorithms. Stars must be provided as a list of pixel positions.

This library works on Linux and macOS but it requires WSL on Windows.

We are not the authors of the Astrometry.net library. You should cite works from https://astrometry.net/biblio.html if you use the Astrometry.net algorithm via this package.

Get started

python3 -m venv .venv
source .venv/bin/activate
pip install astrometry
import astrometry

with astrometry.Solver(
    astrometry.series_5200.index_files(
        cache_directory="astrometry_cache",
        scales={6},
    )
) as solver:

    stars = [
        [388.9140568247906, 656.5003281719216],
        [732.9210858972549, 473.66395545775106],
        [401.03459504299843, 253.788113189415],
        [312.6591868096163, 624.7527729425295],
        [694.6844564647456, 606.8371776658344],
        [741.7233477959561, 344.41284826261443],
        [867.3574610200455, 672.014835980283],
        [1063.546651153479, 593.7844603550848],
        [286.69070190952704, 422.170016812049],
        [401.12779619355155, 16.13543616977013],
        [205.12103484692776, 698.1847350789413],
        [202.88444768690894, 111.24830187635557],
        [339.1627757703069, 86.60739435924549],
    ]

    solution = solver.solve(
        stars=stars,
        size_hint=None,
        position_hint=None,
        solution_parameters=astrometry.SolutionParameters(),
    )

    if solution.has_match():
        print(f"{solution.best_match().center_ra_deg=}")
        print(f"{solution.best_match().center_dec_deg=}")
        print(f"{solution.best_match().scale_arcsec_per_pixel=}")

solve is thread-safe. It can be called any number of times from the same Solver object.

Examples

Use the solver without with

import astrometry

solver = astrometry.Solver(...)
solver.solve(...) # solve can be called multiple times
solver.close() # close the index files used by the solver

Provide size and position hints

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=astrometry.SizeHint(
            lower_arcsec_per_pixel=1.0,
            upper_arcsec_per_pixel=2.0,
        ),
        position_hint=astrometry.PositionHint(
            ra_deg=65.7,
            dec_deg=36.2,
            radius_deg=1.0,
        ),
        solution_parameters=...
    )

Print progress information (download and solve)

import astrometry
import logging

logging.getLogger().setLevel(logging.INFO)

with astrometry.Solver(...) as solver:
    solution = solver.solve(...)

Print field stars metadata

Astrometry extracts metadata from the star index ("series"). See Choosing series for a description of the available data.

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(...)

    if solution.has_match():
        for star in solution.best_match().stars:
            print(f"{star.ra_deg}º, {star.dec_deg}º:", star.metadata)

Calculate field stars pixel positions with astropy

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(...)

    if solution.has_match():
        wcs = solution.best_match().astropy_wcs()
        pixels = wcs.all_world2pix(
            [[star.ra_deg, star.dec_deg] for star in solution.best_match().stars],
            0,
        )
        # pixels is a len(solution.best_match().stars) x 2 numpy array of float values

astropy.wcs.WCS provides many more functions to probe the transformation properties and convert from and to pixel coordinates. See https://docs.astropy.org/en/stable/api/astropy.wcs.WCS.html for details. Astropy (https://pypi.org/project/astropy/) must be installed to use this method.

Print series description and size (without downloading them)

import astrometry

print(astrometry.series_5200_heavy.description)
print(astrometry.series_5200_heavy.size_as_string({2, 3, 4}))

See Choosing Series for a list of available series.

Disable tune-up and distortion

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=...,
        position_hint=...,
        solution_parameters=astrometry.SolutionParameters(
            sip_order=0,
            tune_up_logodds_threshold=None,
        ),
    )

Stop the solver early using the log-odds callback

Return after the first match

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=...,
        position_hint=...,
        solution_parameters=astrometry.SolutionParameters(
            logodds_callback=lambda logodds_list: astrometry.Action.STOP,
        ),
    )

Return early if the best log-odds are larger than 100.0

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=...,
        position_hint=...,
        solution_parameters=astrometry.SolutionParameters(
            logodds_callback=lambda logodds_list: (
                astrometry.Action.STOP
                if logodds_list[0] > 100.0
                else astrometry.Action.CONTINUE
            ),
        ),
    )

Return early if there are at least ten matches

import astrometry

with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=...,
        position_hint=...,
        solution_parameters=astrometry.SolutionParameters(
            logodds_callback=lambda logodds_list: (
                astrometry.Action.STOP
                if len(logodds_list) >= 10.0
                else astrometry.Action.CONTINUE
            ),
        ),
    )

Return early if the three best matches are similar

import astrometry

def logodds_callback(logodds_list: list[float]) -> astrometry.Action:
    if len(logodds_list) < 3:
        return astrometry.Action.CONTINUE
    if logodds_list[1] > logodds_list[0] - 10 and logodds_list[2] > logodds_list[0] - 10:
        return astrometry.Action.STOP
    return astrometry.Action.CONTINUE


with astrometry.Solver(...) as solver:
    solution = solver.solve(
        stars=...,
        size_hint=...,
        position_hint=...,
        solution_parameters=astrometry.SolutionParameters(
            logodds_callback=logodds_callback,
        ),
    )

Choosing series

This library downloads series from http://data.astrometry.net. A solver can be instantiated with multiple series and scales as follows:

import astrometry

with astrometry.Solver(
    astrometry.series_5200.index_files(
        cache_directory="astrometry_cache",
        scales={4, 5, 6},
    )
    + astrometry.series_4200.index_files(
        cache_directory="astrometry_cache",
        scales={6, 7, 12},
    )
) as solver:
    ...

Astrometry.net gives the following recommendations to choose a scale:

Each index file contains a large number of “skymarks” (landmarks for the sky) that allow our solver to identify your images. The skymarks contained in each index file have sizes (diameters) within a narrow range. You probably want to download index files whose quads are, say, 10% to 100% of the sizes of the images you want to solve.

For example, let’s say you have some 1-degree square images. You should grab index files that contain skymarks of size 0.1 to 1 degre

Related Skills

View on GitHub
GitHub Stars44
CategoryDevelopment
Updated8d ago
Forks4

Languages

Python

Security Score

90/100

Audited on Mar 30, 2026

No findings