-
-
Notifications
You must be signed in to change notification settings - Fork 58
STC-S draft implementation #619
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
5fff307
13f7cab
b055e0f
b662a25
cb65912
58c0e07
42b8fce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,27 +1,24 @@ | ||
| .. These are ReST substitutions and links that can be used throughout the docs | ||
| .. (and docstrings) because they are added to ``docs/conf.py::rst_epilog``. | ||
|
|
||
| .. ------------------------------------------------------------------ | ||
| .. RST SUBSTITUTIONS | ||
|
|
||
| .. NumPy | ||
| .. |ndarray| replace:: :class:`numpy.ndarray` | ||
|
|
||
| .. Astropy | ||
| .. |Angle| replace:: `astropy.coordinates.Angle` | ||
| .. |Latitude| replace:: `astropy.coordinates.Latitude` | ||
| .. |Longitude| replace:: :class:`astropy.coordinates.Longitude` | ||
| .. |SkyCoord| replace:: :class:`astropy.coordinates.SkyCoord` | ||
| .. |Table| replace:: :class:`astropy.table.Table` | ||
| .. |QTable| replace:: :class:`astropy.table.QTable` | ||
| .. |Quantity| replace:: :class:`astropy.units.Quantity` | ||
| .. |Unit| replace:: :class:`astropy.units.UnitBase` | ||
|
|
||
| .. Regions | ||
| .. |PixCoord| replace:: `~regions.PixCoord` | ||
| .. |RegionMeta| replace:: `~regions.RegionMeta` | ||
| .. |RegionVisual| replace:: `~regions.RegionVisual` | ||
|
|
||
| .. Matplotlib | ||
| .. _Matplotlib: https://matplotlib.org/ | ||
| .. |Patch| replace:: `~matplotlib.patches.Patch` | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any region to accept any of these changes. |
||
| .. _Astropy: https://www.astropy.org/ | ||
| .. _astropy.io.fits: https://docs.astropy.org/en/stable/io/fits/ | ||
| .. _astropy.table.Table: https://docs.astropy.org/en/stable/table/ | ||
| .. _astropy.wcs: https://docs.astropy.org/en/stable/wcs/ | ||
| .. _Astropy units: https://docs.astropy.org/en/stable/units/ | ||
| .. _Astropy WCS: https://docs.astropy.org/en/stable/wcs/ | ||
| .. _CASA: https://casa.nrao.edu/ | ||
| .. _configparser: https://docs.python.org/3/library/configparser.html | ||
| .. _coordinated package: https://www.astropy.org/affiliated/ | ||
| .. _DS9: http://ds9.si.edu/site/Home.html | ||
| .. _File Formats: http://ds9.si.edu/doc/ref/region.html | ||
| .. _FITS: https://fits.gsfc.nasa.gov/ | ||
| .. _FITS Region Binary Table: https://fits.gsfc.nasa.gov/registry/region.html | ||
| .. _GitHub repository: https://github.com/astropy/regions | ||
| .. _CASA Region Text Format: https://casadocs.readthedocs.io/en/stable/notebooks/image_analysis.html#Region-File-Format | ||
| .. _matplotlib: https://matplotlib.org/ | ||
| .. _pip: https://pip.pypa.io/en/stable/ | ||
| .. _PyPI: https://pypi.org/project/regions/ | ||
| .. _SAOImageDS9: http://ds9.si.edu/site/Home.html | ||
| .. _shapely: https://pypi.org/project/Shapely/ | ||
| .. _conda: https://conda.io/en/latest/ | ||
| .. _IVOA STC-S Note: https://www.ivoa.net/documents/Notes/STC-S/20091030/NOTE-STC-S-1.33-20091030.html | ||
| .. _STC-S: https://www.ivoa.net/documents/Notes/STC-S/20091030/NOTE-STC-S-1.33-20091030.html | ||
| .. _IVOA: https://www.ivoa.net/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,233 @@ | ||
| # STC-S I/O Module for astropy-regions | ||
|
|
||
| This module provides support for reading and writing regions in the **STC-S (Space-Time Coordinate String)** format, which is an IVOA (International Virtual Observatory Alliance) standard for describing spatial and temporal regions and coordinates. | ||
|
|
||
| ## Overview | ||
|
|
||
| The STC-S format provides a string representation for astronomical regions that is: | ||
| - Standardized by the IVOA | ||
| - Human-readable and compact | ||
| - Suitable for describing both sky and pixel coordinates | ||
| - Compatible with various coordinate systems and reference frames | ||
|
|
||
| ## Features | ||
|
|
||
| - **Reading**: Parse STC-S strings and files into `regions.Region` objects | ||
| - **Writing**: Serialize `regions.Region` objects to STC-S format | ||
| - **Round-trip**: Full round-trip conversion preserving region properties | ||
| - **Multiple Shapes**: Support for circles, ellipses, boxes/rectangles, polygons, and points | ||
| - **Coordinate Systems**: Support for ICRS, FK5, FK4, Galactic, Ecliptic, and Image coordinates | ||
| - **Reference Positions**: Support for various reference positions (Barycenter, Geocenter, Topocenter, etc.) | ||
|
|
||
| ## Supported Shapes | ||
|
|
||
| | STC-S Shape | astropy-regions Class | Description | | ||
| |-------------|----------------------|-------------| | ||
| | `Circle` | `CircleSkyRegion` / `CirclePixelRegion` | Circular region | | ||
| | `Ellipse` | `EllipseSkyRegion` / `EllipsePixelRegion` | Elliptical region | | ||
| | `Box` | `RectangleSkyRegion` / `RectanglePixelRegion` | Rectangular region | | ||
| | `Polygon` | `PolygonSkyRegion` / `PolygonPixelRegion` | Polygonal region | | ||
| | `Position` | `PointSkyRegion` / `PointPixelRegion` | Point region | | ||
|
|
||
| ## Usage Examples | ||
|
|
||
| ### Reading STC-S Files | ||
|
|
||
| ```python | ||
| from regions import Regions | ||
|
|
||
| # Read from file | ||
| regions = Regions.read('regions.stcs', format='stcs') | ||
|
|
||
| # Parse STC-S string directly | ||
| stcs_string = """ | ||
| # Example STC-S regions | ||
| Circle ICRS BARYCENTER 180.0 10.0 0.5 | ||
| Ellipse ICRS BARYCENTER 150.0 -20.0 1.0 0.5 45.0 | ||
| Position FK5 GEOCENTER 85.0 -15.0 | ||
| """ | ||
| regions = Regions.parse(stcs_string, format='stcs') | ||
| ``` | ||
|
|
||
| ### Writing STC-S Files | ||
|
|
||
| ```python | ||
| import astropy.units as u | ||
| from astropy.coordinates import SkyCoord | ||
| from regions import Regions | ||
| from regions.shapes import CircleSkyRegion, PointSkyRegion | ||
|
|
||
| # Create regions | ||
| center = SkyCoord(180.0, 10.0, unit='degree', frame='icrs') | ||
| circle = CircleSkyRegion(center=center, radius=0.5 * u.degree) | ||
|
|
||
| center2 = SkyCoord(85.0, -15.0, unit='degree', frame='fk5') | ||
| point = PointSkyRegion(center=center2) | ||
|
|
||
| regions = Regions([circle, point]) | ||
|
|
||
| # Write to file | ||
| regions.write('output.stcs', format='stcs', overwrite=True) | ||
|
|
||
| # Serialize to string | ||
| stcs_string = regions.serialize(format='stcs') | ||
| print(stcs_string) | ||
| ``` | ||
|
|
||
| ### Working with Pixel Coordinates | ||
|
|
||
| ```python | ||
| from regions.core import PixCoord | ||
| from regions.shapes import CirclePixelRegion | ||
|
|
||
| # Create pixel region | ||
| center = PixCoord(100.5, 200.3) | ||
| pixel_circle = CirclePixelRegion(center=center, radius=15.0) | ||
|
|
||
| # Serialize | ||
| stcs_string = pixel_circle.serialize(format='stcs') | ||
| # Output: "Circle IMAGE UNKNOWN 100.5 200.3 15" | ||
| ``` | ||
|
|
||
| ## STC-S Format Specification | ||
|
|
||
| ### Basic Syntax | ||
|
|
||
| ``` | ||
| <Shape> <Frame> <RefPos> <Coordinates> [<Parameters>] | ||
| ``` | ||
|
|
||
| ### Examples | ||
|
|
||
| ```stcs | ||
| # Circle: center_lon center_lat radius | ||
| Circle ICRS BARYCENTER 180.0 10.0 0.5 | ||
|
|
||
| # Ellipse: center_lon center_lat semi_major semi_minor angle | ||
| Ellipse ICRS BARYCENTER 150.0 -20.0 1.0 0.5 45.0 | ||
|
|
||
| # Box: center_lon center_lat width height angle | ||
| Box ICRS BARYCENTER 120.0 30.0 2.0 1.0 0.0 | ||
|
|
||
| # Polygon: lon1 lat1 lon2 lat2 lon3 lat3 ... | ||
| Polygon ICRS BARYCENTER 45.0 45.0 50.0 45.0 50.0 50.0 45.0 50.0 | ||
|
|
||
| # Position: lon lat | ||
| Position FK5 GEOCENTER 85.0 -15.0 | ||
|
|
||
| # Pixel coordinates | ||
| Circle IMAGE UNKNOWN 100.5 200.3 15.0 | ||
| ``` | ||
|
|
||
| ### Coordinate Frames | ||
|
|
||
| - **ICRS**: International Celestial Reference System | ||
| - **FK5**: Fifth Fundamental Catalogue (J2000.0) | ||
| - **FK4**: Fourth Fundamental Catalogue (B1950.0) | ||
| - **GALACTIC**: Galactic coordinate system | ||
| - **ECLIPTIC**: Ecliptic coordinate system | ||
| - **IMAGE**: Pixel/image coordinates | ||
|
|
||
| ### Reference Positions | ||
|
|
||
| - **BARYCENTER**: Solar system barycenter | ||
| - **GEOCENTER**: Earth center | ||
| - **TOPOCENTER**: Earth surface/topocentric | ||
| - **HELIOCENTER**: Sun center | ||
| - **LSR**: Local Standard of Rest | ||
| - **UNKNOWN**: Unspecified reference | ||
|
|
||
| ## File Format | ||
|
|
||
| STC-S files typically have extensions: | ||
| - `.stcs` | ||
| - `.stc` | ||
| - `.stcs.txt` | ||
| - `.stc.txt` | ||
|
|
||
| Files can contain: | ||
| - Comments starting with `#` | ||
| - Multiple regions, one per line | ||
| - Blank lines (ignored) | ||
|
|
||
| Example file: | ||
| ```stcs | ||
| # STC-S region file | ||
| # Generated by astropy-regions | ||
|
|
||
| # Central source | ||
| Circle ICRS BARYCENTER 180.0 10.0 0.5 | ||
|
|
||
| # Extended emission | ||
| Ellipse ICRS BARYCENTER 150.0 -20.0 1.0 0.5 45.0 | ||
|
|
||
| # Point sources | ||
| Position FK5 GEOCENTER 85.0 -15.0 | ||
| Position FK5 GEOCENTER 90.0 -10.0 | ||
| ``` | ||
|
|
||
| ## Implementation Details | ||
|
|
||
| The STC-S module consists of: | ||
|
|
||
| - **`core.py`**: Core parsing functions, mappings, and utilities | ||
| - **`connect.py`**: File format identification and registry | ||
| - **`read.py`**: STC-S reading and parsing functionality | ||
| - **`write.py`**: STC-S writing and serialization functionality | ||
| - **`tests/`**: Comprehensive test suite | ||
|
|
||
| ### Key Functions | ||
|
|
||
| - `validate_stcs_string()`: Validate STC-S format | ||
| - `parse_coordinate_frame()`: Extract coordinate frame and reference position | ||
| - `parse_numbers()`: Parse numeric parameters | ||
| - `_parse_stcs()`: Main parsing function | ||
| - `_serialize_stcs()`: Main serialization function | ||
|
|
||
| ## References | ||
|
|
||
| - [IVOA STC-S Standard](https://www.ivoa.net/documents/Notes/STC-S/20091030/NOTE-STC-S-1.33-20091030.html) | ||
| - [CDS STC-S Rust Implementation](https://github.com/cds-astro/cds-stc-rust/) | ||
| - [astropy-regions Issue #21](https://github.com/astropy/regions/issues/21) | ||
|
|
||
| ## Testing | ||
|
|
||
| Run the test suite: | ||
| ```bash | ||
| # Run all STC-S tests | ||
| pytest regions/io/stcs/tests/ | ||
|
|
||
| # Run specific test file | ||
| pytest regions/io/stcs/tests/test_stcs.py | ||
|
|
||
| # Run with verbose output | ||
| pytest regions/io/stcs/tests/ -v | ||
| ``` | ||
|
|
||
| Test data files are located in `regions/io/stcs/tests/data/`. | ||
|
|
||
| ## Contributing | ||
|
|
||
| When contributing to the STC-S module: | ||
|
|
||
| 1. Follow the existing code style and patterns from the DS9 module | ||
| 2. Add comprehensive tests for new functionality | ||
| 3. Update documentation and examples | ||
| 4. Ensure round-trip conversions work correctly | ||
| 5. Test with various coordinate systems and shapes | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no need for this - these were basically instructions to the AI |
||
| ## Known Limitations | ||
|
|
||
| - Complex STC-S features like time coordinates are not yet supported | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ... weird commentary, are they so complex? |
||
| - Union, intersection, and other compound operations are not implemented | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. seems reasonable - does the standard even support them?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes: "Optionally, compound sub-phrases may be recognized for compound Regions. Under those rules the CoordinateArea operational identifier (Union, Intersection, or Difference) precedes the CoordinateFrame component which, in turn, is followed by two or more (if applicable) CoordinateArea components; these CoordinateArea identifiers may be preceded by the negation operator Not. The arguments for these operators must be enclosed in parentheses. For Union and Intersection the argument may contain two or more elements; for Difference it must contain exactly two; and for Not it must contain only one. The enclosure in parentheses is merely intended to allow nesting and avoid ambiguities." |
||
| - Some advanced STC-S syntax elements are not parsed | ||
| - Error handling could be more detailed for malformed input | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| - Support for temporal coordinates and regions | ||
| - Compound region operations (Union, Intersection, etc.) | ||
| - More comprehensive error messages | ||
| - Support for additional coordinate systems | ||
| - Integration with STC XML format | ||
| - Performance optimizations for large files | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
| """ | ||
| This subpackage provides tools for reading and writing STC-S region files. | ||
|
|
||
| The Space-Time Coordinate (STC) string representation (STC-S) is an IVOA | ||
| standard for describing spatial and temporal regions and coordinates. | ||
| """ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| # Licensed under a 3-clause BSD style license - see LICENSE.rst | ||
|
|
||
| from astropy.utils.data import get_readable_fileobj | ||
|
|
||
| from regions.core import Region, Regions | ||
| from regions.core.registry import RegionsRegistry | ||
|
|
||
| __all__ = [] | ||
|
|
||
|
|
||
| @RegionsRegistry.register(Region, 'identify', 'stcs') | ||
| @RegionsRegistry.register(Regions, 'identify', 'stcs') | ||
| def is_stcs(methodname, filepath): | ||
| """ | ||
| Identify an STC-S region file. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| methodname : {'read', 'write'} | ||
| The method name called that needs auto-identification. | ||
|
|
||
| filepath : str | ||
| The path to the file. | ||
|
|
||
| Returns | ||
| ------- | ||
| result : bool | ||
| Returns `True` if the given file is an STC-S region file. | ||
| """ | ||
| all_exten = ('.stcs', '.stc', '.stcs.txt', '.stc.txt') | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do any of these files exist in the wild? I'm happy enough to establish this as a new filename convention otherwise. |
||
| exten = {'read': all_exten, 'write': all_exten[0:2]} | ||
|
|
||
| if methodname == 'write': | ||
| return filepath.lower().endswith(exten[methodname]) | ||
|
|
||
| elif methodname == 'read': | ||
| if (isinstance(filepath, str) | ||
| and filepath.lower().endswith(exten[methodname])): | ||
| return True | ||
| else: | ||
| # Check file content for STC-S keywords | ||
| try: | ||
| with get_readable_fileobj(filepath, encoding='utf-8') as fileobj: | ||
| # Read first few lines to check for STC-S content | ||
| content = fileobj.read(512) # Read first 512 characters | ||
| if content: | ||
| # Look for common STC-S keywords | ||
| stcs_keywords = ['Circle', 'Ellipse', 'Box', 'Polygon', 'Position', | ||
| 'ICRS', 'FK5', 'FK4', 'GALACTIC', 'ECLIPTIC'] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. these are not unique - not good to use. |
||
| content_upper = content.upper() | ||
| return any(keyword.upper() in content_upper for keyword in stcs_keywords) | ||
| return False | ||
| except (UnicodeDecodeError, OSError): | ||
| return False | ||
|
|
||
| else: | ||
| return False | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably should reject this change - no reason to exclude inheritance diagrams, right?