diff --git a/astrocut/__init__.py b/astrocut/__init__.py
index 9249d8e4..fc30bdd3 100644
--- a/astrocut/__init__.py
+++ b/astrocut/__init__.py
@@ -27,3 +27,4 @@ class UnsupportedPythonError(Exception):
from .cutouts import fits_cut, img_cut, normalize_img # noqa
from .cutout_processing import (path_to_footprints, center_on_path, # noqa
CutoutsCombiner, build_default_combine_function) # noqa
+ from .asdf_cutouts import asdf_cut, get_center_pixel # noqa
diff --git a/astrocut/asdf_cutouts.py b/astrocut/asdf_cutouts.py
index b72ef6dc..3f039a44 100644
--- a/astrocut/asdf_cutouts.py
+++ b/astrocut/asdf_cutouts.py
@@ -16,7 +16,8 @@
def _get_cloud_http(s3_uri: str) -> str:
- """ Get the HTTP URI of a cloud resource from an S3 URI
+ """
+ Get the HTTP URI of a cloud resource from an S3 URI.
Parameters
----------
@@ -24,7 +25,7 @@ def _get_cloud_http(s3_uri: str) -> str:
the S3 URI of the cloud resource
"""
# create file system
- fs = s3fs.S3FileSystem(anon=True)
+ fs = s3fs.S3FileSystem()
# open resource and get URL
with fs.open(s3_uri, 'rb') as f:
@@ -32,7 +33,8 @@ def _get_cloud_http(s3_uri: str) -> str:
def get_center_pixel(gwcsobj: gwcs.wcs.WCS, ra: float, dec: float) -> tuple:
- """ Get the center pixel from a roman 2d science image
+ """
+ Get the center pixel from a Roman 2D science image.
For an input RA, Dec sky coordinate, get the closest pixel location
on the input Roman image.
@@ -40,16 +42,16 @@ def get_center_pixel(gwcsobj: gwcs.wcs.WCS, ra: float, dec: float) -> tuple:
Parameters
----------
gwcsobj : gwcs.wcs.WCS
- the Roman GWCS object
+ The Roman GWCS object.
ra : float
- the input Right Ascension
+ The input right ascension.
dec : float
- the input Declination
+ The input declination.
Returns
-------
tuple
- the pixel position, FITS wcs object
+ The pixel position, FITS wcs object
"""
# Convert the gwcs object to an astropy FITS WCS header
@@ -73,11 +75,12 @@ def get_center_pixel(gwcsobj: gwcs.wcs.WCS, ra: float, dec: float) -> tuple:
return (row, col), wcs_updated
-def get_cutout(data: asdf.tags.core.ndarray.NDArrayType, coords: Union[tuple, SkyCoord],
- wcs: astropy.wcs.wcs.WCS = None, size: int = 20, outfile: str = "example_roman_cutout.fits",
- write_file: bool = True, fill_value: Union[int, float] = np.nan,
- gwcsobj: gwcs.wcs.WCS = None) -> astropy.nddata.Cutout2D:
- """ Get a Roman image cutout
+def _get_cutout(data: asdf.tags.core.ndarray.NDArrayType, coords: Union[tuple, SkyCoord],
+ wcs: astropy.wcs.wcs.WCS = None, size: int = 20, outfile: str = "example_roman_cutout.fits",
+ write_file: bool = True, fill_value: Union[int, float] = np.nan,
+ gwcsobj: gwcs.wcs.WCS = None) -> astropy.nddata.Cutout2D:
+ """
+ Get a Roman image cutout.
Cut out a square section from the input image data array. The ``coords`` can either be a tuple of x, y
pixel coordinates or an astropy SkyCoord object, in which case, a wcs is required. Writes out a
@@ -154,7 +157,8 @@ def get_cutout(data: asdf.tags.core.ndarray.NDArrayType, coords: Union[tuple, Sk
def _write_fits(cutout: astropy.nddata.Cutout2D, outfile: str = "example_roman_cutout.fits"):
- """ Write cutout as FITS file
+ """
+ Write cutout as FITS file.
Parameters
----------
@@ -173,7 +177,8 @@ def _write_fits(cutout: astropy.nddata.Cutout2D, outfile: str = "example_roman_c
def _slice_gwcs(gwcsobj: gwcs.wcs.WCS, slices: Tuple[slice, slice]) -> gwcs.wcs.WCS:
- """ Slice the original gwcs object
+ """
+ Slice the original gwcs object.
"Slices" the original gwcs object down to the cutout shape. This is a hack
until proper gwcs slicing is in place a la fits WCS slicing. The ``slices``
@@ -211,7 +216,8 @@ def _slice_gwcs(gwcsobj: gwcs.wcs.WCS, slices: Tuple[slice, slice]) -> gwcs.wcs.
def _write_asdf(cutout: astropy.nddata.Cutout2D, gwcsobj: gwcs.wcs.WCS, outfile: str = "example_roman_cutout.asdf"):
- """ Write cutout as ASDF file
+ """
+ Write cutout as ASDF file.
Parameters
----------
@@ -236,32 +242,33 @@ def _write_asdf(cutout: astropy.nddata.Cutout2D, gwcsobj: gwcs.wcs.WCS, outfile:
def asdf_cut(input_file: str, ra: float, dec: float, cutout_size: int = 20,
output_file: str = "example_roman_cutout.fits",
write_file: bool = True, fill_value: Union[int, float] = np.nan) -> astropy.nddata.Cutout2D:
- """ Preliminary proof-of-concept functionality.
+ """
+ Takes a single ASDF input file (`input_file`) and generates a cutout of designated size `cutout_size`
+ around the given coordinates (`coordinates`).
- Takes a single ASDF input file (``input_file``) and generates a cutout of designated size ``cutout_size``
- around the given coordinates (``coordinates``).
+ Preliminary proof-of-concept functionality.
Parameters
----------
input_file : str
- the input ASDF file
+ The input ASDF file.
ra : float
- the Right Ascension of the central cutout
+ The right ascension of the central cutout.
dec : float
- the Declination of the central cutout
- cutout_size : int, optional
- the image cutout pixel size, by default 20
- output_file : str, optional
- the name of the output cutout file, by default "example_roman_cutout.fits"
- write_file : bool, by default True
- Flag to write the cutout to a file or not
- fill_value: int | float, by default np.nan
- The fill value for pixels outside the original image.
+ The declination of the central cutout.
+ cutout_size : int
+ Optional, default 20. The image cutout pixel size.
+ output_file : str
+ Optional, default "example_roman_cutout.fits". The name of the output cutout file.
+ write_file : bool
+ Optional, default True. Flag to write the cutout to a file or not.
+ fill_value: int | float
+ Optional, default `np.nan`. The fill value for pixels outside the original image.
Returns
-------
astropy.nddata.Cutout2D:
- an image cutout object
+ An image cutout object.
"""
# if file comes from AWS cloud bucket, get HTTP URL to open with asdf
@@ -278,5 +285,5 @@ def asdf_cut(input_file: str, ra: float, dec: float, cutout_size: int = 20,
pixel_coordinates, wcs = get_center_pixel(gwcsobj, ra, dec)
# create the 2d image cutout
- return get_cutout(data, pixel_coordinates, wcs, size=cutout_size, outfile=output_file,
- write_file=write_file, fill_value=fill_value, gwcsobj=gwcsobj)
+ return _get_cutout(data, pixel_coordinates, wcs, size=cutout_size, outfile=output_file,
+ write_file=write_file, fill_value=fill_value, gwcsobj=gwcsobj)
diff --git a/astrocut/tests/test_asdf_cut.py b/astrocut/tests/test_asdf_cut.py
index 0193674d..70c0c968 100644
--- a/astrocut/tests/test_asdf_cut.py
+++ b/astrocut/tests/test_asdf_cut.py
@@ -13,7 +13,7 @@
from astropy.wcs.utils import pixel_to_skycoord
from gwcs import wcs
from gwcs import coordinate_frames as cf
-from astrocut.asdf_cutouts import get_center_pixel, get_cutout, asdf_cut, _slice_gwcs, _get_cloud_http
+from astrocut.asdf_cutouts import get_center_pixel, asdf_cut, _get_cutout, _slice_gwcs, _get_cloud_http
def make_wcs(xsize, ysize, ra=30., dec=45.):
@@ -137,7 +137,7 @@ def test_get_cutout(output, fakedata, quantity):
data = data.value
# create cutout
- cutout = get_cutout(data, skycoord, wcs, size=10, outfile=output_file)
+ cutout = _get_cutout(data, skycoord, wcs, size=10, outfile=output_file)
assert_same_coord(5, 10, cutout, wcs)
@@ -185,7 +185,7 @@ def test_fail_write_asdf(fakedata, output):
data, gwcs = fakedata
skycoord = gwcs(25, 25, with_units=True)
wcs = WCS(gwcs.to_fits_sip())
- get_cutout(data, skycoord, wcs, size=10, outfile=output_file)
+ _get_cutout(data, skycoord, wcs, size=10, outfile=output_file)
def test_cutout_nofile(make_file, output):
@@ -217,7 +217,7 @@ def test_cutout_poles(makefake):
wcs = WCS(gwcs.to_fits_sip())
# get cutout
- cutout = get_cutout(data, cc, wcs, size=50, write_file=False)
+ cutout = _get_cutout(data, cc, wcs, size=50, write_file=False)
assert_same_coord(5, 10, cutout, wcs)
# check cutout contains all data
@@ -232,7 +232,7 @@ def test_fail_cutout_outside(fakedata):
with pytest.raises(RuntimeError, match='Could not create 2d cutout. The requested '
'cutout does not overlap with the original image'):
- get_cutout(data, cc, wcs, size=50, write_file=False)
+ _get_cutout(data, cc, wcs, size=50, write_file=False)
def assert_same_coord(x, y, cutout, wcs):
@@ -251,7 +251,7 @@ def test_partial_cutout(makefake, asint, fill):
wcs = WCS(gwcs.to_fits_sip())
cc = coord.SkyCoord(29.999, 44.998, unit=u.degree)
- cutout = get_cutout(data, cc, wcs, size=50, write_file=False, fill_value=fill)
+ cutout = _get_cutout(data, cc, wcs, size=50, write_file=False, fill_value=fill)
assert cutout.shape == (50, 50)
if asint:
assert -9999 in cutout.data
@@ -266,7 +266,7 @@ def test_bad_fill(makefake):
wcs = WCS(gwcs.to_fits_sip())
cc = coord.SkyCoord(29.999, 44.998, unit=u.degree)
with pytest.raises(ValueError, match='fill_value is inconsistent with the data type of the input array'):
- get_cutout(data, cc, wcs, size=50, write_file=False)
+ _get_cutout(data, cc, wcs, size=50, write_file=False)
def test_cutout_raedge(makefake):
@@ -284,7 +284,7 @@ def test_cutout_raedge(makefake):
wcs = WCS(gg.to_fits_sip())
# get cutout
- cutout = get_cutout(data, cc, wcs, size=100, write_file=False)
+ cutout = _get_cutout(data, cc, wcs, size=100, write_file=False)
assert_same_coord(5, 10, cutout, wcs)
# assert the RA cutout bounds are > 359 and < 0
@@ -299,7 +299,7 @@ def test_slice_gwcs(fakedata):
skycoord = gwcsobj(250, 250)
wcs = WCS(gwcsobj.to_fits_sip())
- cutout = get_cutout(data, skycoord, wcs, size=50, write_file=False)
+ cutout = _get_cutout(data, skycoord, wcs, size=50, write_file=False)
sliced = _slice_gwcs(gwcsobj, cutout.slices_original)
@@ -329,6 +329,6 @@ def test_get_cloud_http(mock_s3fs):
http_uri = _get_cloud_http(s3_uri)
assert http_uri == HTTP_URI
- mock_s3fs.assert_called_once_with(anon=True)
+ mock_s3fs.assert_called_once_with()
mock_fs.open.assert_called_once_with(s3_uri, 'rb')
mock_file.url.assert_called_once()
diff --git a/docs/astrocut/file_formats.rst b/docs/astrocut/file_formats.rst
index 5ca7fc0b..685381fa 100644
--- a/docs/astrocut/file_formats.rst
+++ b/docs/astrocut/file_formats.rst
@@ -39,6 +39,26 @@ it contains the name of the file the cutout comes from.
+ASDF Cutout Files
+==================
+
+ASDF files output by `asdf_cut` are a minimal tree structure that mirrors the format of the original Roman image file.
+
+.. code-block:: python
+
+ asdf_cutout = {
+ "roman": {
+ "meta": {
+ "wcs" - the gwcs of the cutout
+ },
+ "data" - the cutout data
+ }
+ }
+
+`wcs` is the original `gwcs` object from the input ASDF file that has been sliced into the shape of the cutout.
+
+
+
Cube Files
==========
diff --git a/docs/astrocut/index.rst b/docs/astrocut/index.rst
index deace98f..5b93052e 100644
--- a/docs/astrocut/index.rst
+++ b/docs/astrocut/index.rst
@@ -17,7 +17,7 @@ Three main areas of functionality are included:
-FITS file image cutouts
+FITS File Image Cutouts
=======================
These functions provide general purpose astronomical cutout functionality for FITS files.
@@ -25,7 +25,7 @@ There are two main cutout functions, `~astrocut.fits_cut` for creating cutout FI
and `~astrocut.img_cut` for creating cutout JPG or PNG files. An image normalization
(`~astrocut.normalize_img`) function is also available.
-Creating FITS cutouts
+Creating FITS Cutouts
---------------------
The function `~astrocut.fits_cut` takes one or more FITS files and performs the same cutout
@@ -107,7 +107,7 @@ The cutout(s) can also be returned in memory as `~astropy.io.fits.HDUList` objec
1 CUTOUT 1 ImageHDU 97 (100, 100) float32
-Creating image cutouts
+Creating Image Cutouts
----------------------
The function `~astrocut.img_cut` takes one or more FITS files and performs the same cutout
@@ -179,7 +179,7 @@ the same Sector, camera, and CCD.
If you are creating a small number of cutouts, the TESSCut web service
may suit your needs: `mast.stsci.edu/tesscut `_
-Making image cubes
+Making Image Cubes
------------------
.. important::
@@ -250,7 +250,7 @@ The output image cube file format is described `here `__.
+
+.. code-block:: python
+
+ >>> from astrocut import asdf_cut
+ >>> from astropy.coordinates import SkyCoord
+ >>> from astropy.io import fits
+
+ >>> input_file = "" # Path to local ASDF file or URI
+
+ >>> center_coord = SkyCoord("80.15189743 29.74561219", unit='deg')
+
+ >>> cutout_file = asdf_cut(input_file, center_coord.ra, center_coord.dec, cutout_size=200,
+ ... output_file="roman-demo.fits") #doctest: +SKIP
+
+ >>> cutout_hdulist = fits.open(cutout_file) #doctest: +SKIP
+ >>> cutout_hdulist.info() #doctest: +SKIP
+ Filename: roman-demo.fits
+ No. Name Ver Type Cards Dimensions Format
+ 0 PRIMARY 1 PrimaryHDU 25 (200, 200) float32
+
+`asdf_cut` accepts S3 URIs to perform cutouts on ASDF files from the cloud.
+In this example, a cutout is performed on a cloud file and written as an ASDF file. The cutout ASDF file format is described `here `__.
+
+.. code-block:: python
+
+ >>> from astrocut import asdf_cut
+ >>> from astropy.coordinates import SkyCoord
+
+ >>> s3_uri = "s3://..." # Complete URI
+
+ >>> center_coord = SkyCoord("80.15189743 29.74561219", unit='deg')
+
+ >>> cutout_file = asdf_cut(s3_uri, center_coord.ra, center_coord.dec, cutout_size=200,
+ ... output_file="roman-demo.asdf") #doctest: +SKIP
+
+When requesting a cutout that is partially outside of image bounds, the `fill_value` parameter is used to preserve the cutout shape and fill outside pixels.
+
+
+
Additional Cutout Processing
============================
-Path-based cutouts
+Path-based Cutouts
------------------
The `~astrocut.center_on_path` function allows the user to take one or more Astrocut cutout
@@ -436,7 +487,7 @@ cutout location/size(s) necesary to cover the entire path.
2 APERTURE 1 ImageHDU 97 (2136, 2078) int32
-Combining cutouts
+Combining Cutouts
-----------------
The `~astrocut.CutoutsCombiner` class allows the user to take one or more Astrocut cutout