Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ Reference/API

.. automodapi:: regions
:no-inheritance-diagram:

.. automodapi:: regions.io.ds9
:no-inheritance-diagram:

.. automodapi:: regions.io.stcs
:no-inheritance-diagram:
Copy link
Copy Markdown
Contributor Author

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?

51 changes: 24 additions & 27 deletions docs/common_links.txt
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`
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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/
4 changes: 4 additions & 0 deletions docs/region_io.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ filename suffix for a particular format.
crtf .crtf `CASA Region Text Format <https://casadocs.readthedocs.io/en/stable/notebooks/image_analysis.html#Region-File-Format>`_
ds9 .reg, .ds9 `DS9 Region Format <http://ds9.si.edu/doc/ref/region.html>`_
fits .fits `FITS Region Binary Table <https://fits.gsfc.nasa.gov/registry/region.html>`_
stcs .stcs, .stc `STC-S Region Format <https://www.ivoa.net/documents/Notes/STC-S/20091030/NOTE-STC-S-1.33-20091030.html>`_
============ ============== ========================

Use the :meth:`~regions.Regions.get_formats` method to get the
Expand All @@ -40,6 +41,7 @@ registered I/O formats as a :class:`~astropy.table.Table`::
crtf Yes Yes Yes Yes Yes
ds9 Yes Yes Yes Yes Yes
fits Yes Yes Yes Yes Yes
stcs Yes Yes Yes Yes Yes


Read
Expand Down Expand Up @@ -171,6 +173,7 @@ formats and methods for the :class:`~regions.Region` subclasses::
crtf No Yes No Yes Yes
ds9 No Yes No Yes Yes
fits No Yes No Yes Yes
stcs No Yes No Yes Yes


Region File Format Limitations
Expand All @@ -181,3 +184,4 @@ Region File Format Limitations

ds9_io
fits_io
stcs_io
4 changes: 4 additions & 0 deletions regions/io/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@
from .fits.core import * # noqa: F401, F403
from .fits.read import * # noqa: F401, F403
from .fits.write import * # noqa: F401, F403
from .stcs.connect import * # noqa: F401, F403
from .stcs.core import * # noqa: F401, F403
from .stcs.read import * # noqa: F401, F403
from .stcs.write import * # noqa: F401, F403
233 changes: 233 additions & 0 deletions regions/io/stcs/README.md
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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems reasonable - does the standard even support them?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
7 changes: 7 additions & 0 deletions regions/io/stcs/__init__.py
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.
"""
57 changes: 57 additions & 0 deletions regions/io/stcs/connect.py
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')
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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']
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The 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
Loading
Loading