Skip to content

Vectorize string input for Angle and SkyCoord - #20236

Open
veyron-kairo wants to merge 5 commits into
astropy:mainfrom
veyron-kairo:vectorize-angle-parsing
Open

Vectorize string input for Angle and SkyCoord#20236
veyron-kairo wants to merge 5 commits into
astropy:mainfrom
veyron-kairo:vectorize-angle-parsing

Conversation

@veyron-kairo

@veyron-kairo veyron-kairo commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Description

This is the input side of #20131, and the counterpart to #20130 which does the output.

Building an Angle or SkyCoord from an array of strings parses them one at a time through PLY, which is most of the cost of reading a coordinate column. Following @mhvk's suggestion on the issue I went with numpy rather than C: parse_angles normalises the separators with np.strings and lets np.loadtxt tokenise the whole array, with anything it doesn't recognise handed back to the existing parser. Only arrays of 32 or more take that path, so scalars and small arrays are untouched.

Angle on a 200k column goes from 2.85 s to 0.12 s, SkyCoord on 200k pairs is about 20x, and reading a 200k row VizieR style catalogue off disk is 28.7x overall, since the parsing was about 99% of it. Peak memory for a million strings drops from 1737 MB to 774 MB.

Output is bit identical to parsing one at a time, as exact float equality rather than a tolerance, over 6160 generated cases, the real VizieR columns in our ascii test data, 50k SkyCoord pairs, and against fractions.Fraction. The tests pin that equivalence, and there's a changelog entry. np.strings.partition only exists from numpy 2.1, so that call goes through np.char.partition below it.

Fixes #20131

Parsing an array of angle strings goes through the PLY parser one element
at a time, which dominates the cost of reading a coordinate column.

Add parse_angles(), which normalises the separators with numpy string
operations and hands the result to numpy.loadtxt, so a whole array is
parsed in a fixed number of passes. Anything it does not recognise is
flagged for the existing per-element parser, so the result is unchanged.

Signed-off-by: Shridhar Panigrahi <sridharpanigrahi2006@gmail.com>
Only for arrays of at least 32 elements, since below that the per-element
parser is quicker and this leaves scalar behaviour untouched.

Signed-off-by: Shridhar Panigrahi <sridharpanigrahi2006@gmail.com>
The array parser has to give the same answer as the existing one, so the
tests check exactly that, for the spellings it recognises, for one it does
not, and for out-of-range fields.

Signed-off-by: Shridhar Panigrahi <sridharpanigrahi2006@gmail.com>
A declination column is full of strings like '+41 16 09', and stripping
signs from anywhere in a field meant those were handed to the per-element
parser instead of being parsed here, losing the speed-up on half the data.
It also let '12-34' through to numpy, which raised its own error rather
than falling back.

Signed-off-by: Shridhar Panigrahi <sridharpanigrahi2006@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  • Do the proposed changes actually accomplish desired goals?
  • Do the proposed changes follow the Astropy coding guidelines?
  • Are tests added/updated as required? If so, do they follow the Astropy testing guidelines?
  • Are docs added/updated as required? If so, do they follow the Astropy documentation guidelines?
  • Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for rebase and squash.
  • Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the bot.
  • Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  • Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  • At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) before merge.

Signed-off-by: Shridhar Panigrahi <sridharpanigrahi2006@gmail.com>
@veyron-kairo

Copy link
Copy Markdown
Contributor Author

@taldcroft @mhvk whenever you have time, please take a look. Thanks!

@pllim pllim added this to the v8.1.0 milestone Aug 13, 2026
@pllim pllim added the benchmark Run benchmarks for a PR label Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmark Run benchmarks for a PR coordinates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parsing angle/coordinate strings is slow — mostly Python (PLY) overhead

2 participants