API documentation

open_image(store: str | dict | list, chunks: dict | None = None, verbose: bool = False, do_sky_coords: bool = True, selection: dict | None = None, compute_mask: bool = True, backend_opts: dict | None = None) → Dataset[source]

Open CASA, FITS or zarr images lazily as an xradio image dataset. The ngCASA image spec is located at https://docs.google.com/spreadsheets/d/1WW0Gl6z85cJVPgtdgW4dxucurHFa06OKGjgoK8OREFA/edit#gid=1719181934

Supported formats:

  • CASA images (casacore tables), read with arcae;

  • FITS images, read with astropy only (arcae is not needed);

  • zarr stores written by write_image() (out_format="zarr", named with the extension .img.zarr), which hold a whole image dataset; zarr stores with other names open too. Stores written by xradio 1.2.3 and earlier, and stores without the schema_version attribute or with an older version, are upgraded to the current schema conventions and version on read.

Several CASA or FITS images are combined into one dataset by passing a dict that maps image types (data group roles such as "sky", "point_spread_function", "primary_beam" or "mask", and "sky_<group>" for the sky image of another data group) to paths, or a list of paths whose image types are detected from their names: tclean product names such as target.psf or target.residual.fits, and the outputs of a write_image() call for a dataset with a single data group (out.base.sky, out.base.point_spread_function, …). The outputs of a write_image() call for several data groups all end in their role, so several of them are sky images (out.deconvolved.sky, out.model.sky, …): open them with a dict keyed by image type, for example {"sky": "out.deconvolved.sky", "sky_model": "out.model.sky", "point_spread_function": "out.deconvolved.model.point_spread_function"}, or one data group at a time. Paths may start with ~, which is expanded to the home directory.

Notes on FITS compatibility and memory mapping:

This function relies on Astropy’s memmap=True to avoid loading full image data into memory. However, not all FITS files support memory-mapped reads. The following FITS types are incompatible with memory mapping:

  1. Compressed images (CompImageHDU). Workaround: decompress the FITS file with tools like funpack, cfitsio, or Astropy’s .scale()/.copy() workflows.

  2. Scaled images, with BSCALE != 1.0 or BZERO != 0.0 (files without BSCALE/BZERO cards, or with BSCALE=1.0 and BZERO=0.0, are supported). These require data rescaling in memory, which disables lazy access: slicing such arrays forces an eager read of the full dataset. Workaround: remove the scaling with Astropy (HDU.data = HDU.data * BSCALE + BZERO) and save a new file.

These cases raise RuntimeError to prevent silent eager loads that can exhaust memory. If you encounter such an error, consider preprocessing the file to make it memory-mappable.

The polarization axis is always returned in canonical (casacore Stokes, Jones matrix) order (I, Q, U, V; RR, RL, LR, LL; XX, XY, YX, YY). FITS cannot store the correlation products in that order, so the FITS writer may reorder the planes in the file; the reader restores the canonical order, so a FITS file (or a CASA image converted from one) with the axis RR, LL, RL, LR opens as RR, RL, LR, LL, every variable with a polarization dimension reordered the same way. CASA and FITS images without a spectral axis open with casacore’s default single channel, and images without a Stokes axis with the polarization ["I"].

Parameters:
  • store (str, dict or list) – Path to the input image, a dict mapping image types (data group roles) to paths, or a list of paths.

  • chunks (dict) – The desired dask chunk size. Only applicable for casacore and fits images. Supported optional keys are ‘l’, ‘m’, ‘frequency’, ‘polarization’, and ‘time’. The supported values are positive integers, indicating the length of a chunk on that particular axis. If a key is missing, then the associated chunk length along that axis is equal to the number of pixels along that axis. For zarr images, this parameter is ignored and the chunk size used to store the arrays in the zarr image is used. ‘l’ represents the longitude like dimension, and ‘m’ represents the latitude like dimension. For aperture images, ‘u’ may be used in place of ‘l’, and ‘v’ in place of ‘m’. To write the image to zarr with write_image()’s chunks or shards, use chunks that are whole numbers of them (FITS reads fastest with whole rows, i.e. ‘l’ left out): other chunks are rechunked when written.

  • verbose (bool) – emit debugging messages? Default is False.

  • do_sky_coords (bool) – Compute SkyCoord at each pixel and add spherical (sky) dimensions as non-dimensional coordinates in the returned xr.Dataset. Only applies to CASA and FITS images; zarr images will have these coordinates added if they were saved with the zarr dataset, and if zarr image didn’t have these coordinates when it was written, the resulting xr.Dataset will not.

  • selection (dict) – The selection of data to return, supported keys are time, polarization, frequency, l (or u if aperture image), m (or v if aperture image) a missing key indicates to return the entire axis length for that dimension. Values can be non-negative integers or slices. Slicing behaves as numpy slicing does, that is the start pixel is included in the selection, and the end pixel is not. An integer selects a single pixel and keeps its dimension (with length 1), as in load_image(). An empty dictionary (the default) indicates that the entire image should be returned. Currently only supported for images stored in zarr format.

  • compute_mask (bool, optional) – If True (default), compute and attach valid data masks when converting from FITS to xds. If False, skip mask computation entirely. This may improve performance if the mask is not required for subsequent processing. It may, however, result in unpredictable behavior for applications that are not designed to handle missing data. It is the user’s responsibility, not the software’s, to ensure that the mask is computed if it is necessary. Currently only implemented for FITS images.

  • backend_opts (dict, optional) – Format- or engine-specific options. For CASA images using arcae, pass {‘ninstances’: N} to pool N C++ table instances for concurrent multi-threaded table reads. Can also be configured globally via the XRADIO_ARCAE_NINSTANCES environment variable. Default is None.

Return type:

xarray.Dataset

load_image(store: str, block_des: dict = None, do_sky_coords=True, backend_opts: dict | None = None) → Dataset[source]

Load an image or portion of an image (subimage).

CASA images and zarr stores are supported (FITS images are opened with open_image()). The selected pixels of CASA images are read into memory when load_image is called. For zarr stores, the selected part is returned lazily, as by open_image() with a selection: the data variables are dask arrays that read the store when they are computed (call .load() on the result to read them into memory). Coordinates are numpy arrays. As in open_image(), zarr stores written by xradio 1.2.3 and earlier, and stores without a schema_version or with an older one, are upgraded to the current schema conventions and version, and the polarization axis is returned in canonical (Jones matrix) order.

Parameters:
  • store (str, dict or list) – Path to the input image (~ is expanded to the home directory), a dict mapping image types (data group roles such as "sky" or "point_spread_function") to the paths of CASA images, or a list of paths whose image types are detected from their names (see open_image()).

  • block_des (dict) – The description of data to return, supported keys are time, polarization, frequency, l (or u if aperture image), m (or v if aperture image) a missing key indicates to return the entire axis length for that dimension. Values can be non-negative integers or slices. Slicing behaves as numpy slicing does, that is the start pixel is included in the selection, and the end pixel is not. An integer selects a single pixel and keeps its dimension (with length 1). An empty dictionary (the default) indicates that the entire image should be returned (read into memory for a CASA image, lazily for a zarr store, see above). Polarization indices refer to the canonical order of the returned dataset (for zarr stores, to the order of the store). TODO I’d really like to rename this parameter “selection”

  • do_sky_coords (bool) – Compute SkyCoord at each pixel and add spherical (sky) dimensions as non-dimensional coordinates in the returned xr.Dataset. Only applies to CASA and FITS images; zarr images will have these coordinates added if they were saved with the zarr dataset, and if zarr image didn’t have these coordinates when it was written, the resulting xr.Dataset will not.

  • backend_opts (dict, optional) – Format- or engine-specific options. For CASA images using arcae, pass {‘ninstances’: N} to pool N C++ table instances. Can also be configured globally via the XRADIO_ARCAE_NINSTANCES environment variable. Default is None.

Return type:

xarray.Dataset

write_image(xds: ~xarray.core.dataset.Dataset, imagename: str, out_format: str = 'casa', overwrite: bool = False, chunks: dict | None = None, shards: dict | None = None, compressor: ~zarr.abc.codec.BytesBytesCodec | None = BloscCodec(_tunable_attrs={'typesize'}, typesize=1, cname=<BloscCname.zstd: 'zstd'>, clevel=5, shuffle=<BloscShuffle.shuffle: 'shuffle'>, blocksize=0)) → list[str][source]

Write an xradio image dataset as CASA, FITS or zarr images.

TODO: I think the user should be permitted to specify data groups to write.

Supported formats:

  • "casa" (the default) writes casacore image tables and needs arcae. Sky plane images (l and m dimensions) and aperture plane images (u and v dimensions) are written; the normalization images, which have neither, are skipped with a warning. A sky image’s flags become its default mask and its beam fit parameters its restoring beam(s).

  • "fits" writes FITS files with astropy only. Only sky plane images are written; other images are skipped with a warning. Flagged pixels are written as NaN, and the polarization planes may be reordered in the file so that they form a FITS STOKES axis (open_image() restores the canonical order).

  • "zarr" writes the whole dataset, with all its data variables, data groups and attributes (including schema_version), to one zarr store, with the chunks, shards and compressor given below.

Zarr store names: image zarr stores have the extension .img.zarr, as processing sets have .ps.zarr. An imagename that ends in .img.zarr (in any case) is kept, a bare .zarr extension is replaced (out.zarr gives out.img.zarr) and any other name gets .img.zarr appended (out gives out.img.zarr); only the end of the name counts, so out.ps.zarr gives out.ps.img.zarr. When the store name differs from imagename, it is logged, and a warning is logged if a file or directory named imagename exists: it is left unchanged (overwrite applies to the store name), so code that still reads imagename would read it, not the new store. Use the returned path to open or extend the store.

CASA and FITS output names: CASA and FITS images hold one image each, so every data variable that is an image of some data group (its sky, point_spread_function, primary_beam, mask, … role) is written once, to its own output. A sky image is written with the flags and beam fit parameters of its data group, and a point spread function with its beam fit parameters; other data variables (for example the flags of a primary beam) are not written, with a warning. When a single image is written, it is named imagename. When several are written, each is named <imagename>.<g1>.<g2>...<gn>.<role>, where g1 to gn are, in data group order, all data groups whose <role> refers to that variable, for example out.base.sky and out.base.point_spread_function, or out.dirty.residual.primary_beam for a primary beam shared by the data groups dirty and residual. For FITS, a .fits extension of imagename (in any case) stays last: img.fits gives img.base.sky.fits.

Overwriting: all output paths (for zarr, the store name with the .img.zarr extension) are determined before anything is written. With overwrite=False, FileExistsError is raised if any of them exists, and nothing is written. The outputs are written into a temporary directory next to imagename and moved into place only when all of them have been written; existing outputs are then replaced (only with overwrite=True). Other files, such as outputs of earlier writes with other names, are left alone. If writing fails, the temporary directory is removed and nothing at the output paths changes, so a dataset opened lazily from imagename can be written back to the same path.

Parameters:
  • xds (xarray.Dataset) – The image dataset to write.

  • imagename (str) – Path of the output image, the base name of the outputs when several images are written, or the name of the zarr store, which gets the .img.zarr extension (see above). ~ is expanded to the home directory, and missing parent directories are created. Only local paths are supported (not URLs such as s3://...).

  • out_format (str) – Format of the output: "casa" (default), "fits" or "zarr" (in any case).

  • overwrite (bool) – If True, replace existing outputs. Default is False.

  • chunks (dict, optional) – Zarr only: the zarr chunk length by dimension of every data variable, e.g. {"frequency": 16, "l": 256, "m": 256}. A dimension that is missing, or given as -1, is one chunk over the whole axis. By default (None) the chunks follow the dask chunks of each data variable. Dask chunks that are not whole numbers of zarr chunks (of shards, with shards) are rechunked before writing, with a log message; see the chunks of open_image() to avoid that.

  • shards (dict, optional) – Zarr only: the shard length by dimension of every data variable, which needs chunks. Each shard length must be a multiple of the chunk length. A dimension that is missing is not sharded (its shard length is the chunk length); -1, or a length of at least the axis, is one shard of whole chunks covering the axis. By default (None) the store is not sharded.

  • compressor (zarr.abc.codec.BytesBytesCodec, optional) – Zarr only: the codec of every data variable and coordinate, by default zarr.codecs.BloscCodec(cname="zstd", clevel=5, shuffle="shuffle"). None disables compression.

Returns:

The paths written, in output order: the zarr store (imagename with the .img.zarr extension), the single CASA or FITS image (imagename) or every output of a multi-image CASA or FITS write, with ~ expanded. Callers that open or write into an output afterwards should use these paths, not imagename.

Return type:

list of str

Raises:
  • FileExistsError – If an output exists and overwrite is False.

  • TypeError – If compressor is neither a zarr v3 bytes-to-bytes codec nor None.

  • ValueError – If out_format is not supported, imagename is a URL, the dataset holds no image the format can store, or chunks, shards or compressor are given for CASA or FITS, or cannot be applied.

make_empty_sky_image(phase_center: list | ndarray, image_size: list | ndarray, cell_size: list | ndarray, frequency_coords: list | ndarray, pol_coords: list | ndarray, time_coords: list | ndarray, direction_reference: str = 'fK5', projection: str = 'SIN', spectral_reference: str = 'lsrk', do_sky_coords: bool = False) → Dataset[source]

Create an image xarray.Dataset with only coordinates (no datavariables). The image dimensionality is time, frequency, polarization, l, m

Parameters:
  • phase_center (array of float, length = 2, units = rad) – Image phase center.

  • image_size (array of int, length = 2) – Number of x and y axis pixels in image.

  • cell_size (array of float, length = 2, units = rad) – Cell size of x and y axis pixels in image.

  • frequency_coords (list or np.ndarray) – The center frequency in Hz of each image channel.

  • pol_coords (list or np.ndarray) – The polarization label of each image polarization, in canonical (casacore Stokes, Jones matrix) order, for example ["I", "Q", "U", "V"], ["RR", "RL", "LR", "LL"] or ["XX", "YY"].

  • time_coords (float, list, np.ndarray, str, datetime or astropy.time.Time) – The time of each temporal plane: numbers are MJD (UTC) days; datetime64 values, ISO time strings, datetime.datetime objects and astropy Time objects are converted to MJD (UTC) days.

  • direction_reference (str, default = 'fk5') – Direction reference frame: 'fk5' (equinox J2000), 'fk4' (equinox B1950), 'icrs' or 'galactic'.

  • projection (str, default = 'SIN') –

  • spectral_reference (str, default = 'lsrk') – Spectral reference frame: a casacore frame ('LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', 'REST', 'GALACTO', 'LGROUP', 'CMB'), a FITS SPECSYS value ('BARYCENT', …) or a schema observer ('lsrk', 'gcrs', …), in any case. The astropy frames 'icrs', 'hcrs' and 'lsr', which have no casacore equivalent, are accepted too, but images in them cannot be written to CASA or FITS.

  • do_sky_coords (bool) – If True, compute SkyCoord at each pixel and add spherical (sky) dimensions as non-dimensional coordinates in the returned xr.Dataset.

Return type:

xarray.Dataset

Raises:
  • TypeError – If time_coords are neither numbers nor times (for example timedelta64 durations or booleans).

  • ValueError – If pol_coords are not in canonical order, or spectral_reference is not a spectral reference frame.

make_empty_aperture_image(phase_center: list[float] | ndarray, image_size: list[int] | ndarray, sky_image_cell_size: list[float] | ndarray, frequency_coords: list[float] | ndarray, pol_coords: list[str] | ndarray, time_coords: list[float] | ndarray, direction_reference: str = 'fk5', projection: str = 'SIN', spectral_reference: str = 'lsrk') → Dataset[source]

Create an aperture (uv) mage xarray.Dataset with only coordinates (no datavariables). The image dimensionality is time, frequency, polarization, u, v

Parameters:
  • phase_center (array of float, length = 2, units = rad) – Image phase center.

  • image_size (array of int, length = 2) – Number of x and y axis pixels in image.

  • sky_image_cell_size (array of float, length = 2, units = rad) – Cell size of x and y axis pixels in sky image, used to get cell size in uv image

  • frequency_coords (list or np.ndarray) – The center frequency in Hz of each image channel.

  • pol_coords (list or np.ndarray) – The polarization label of each image polarization, in canonical (casacore Stokes, Jones matrix) order, for example ["I", "Q", "U", "V"], ["RR", "RL", "LR", "LL"] or ["XX", "YY"].

  • time_coords (float, list, np.ndarray, str, datetime or astropy.time.Time) – The time of each temporal plane: numbers are MJD (UTC) days; datetime64 values, ISO time strings, datetime.datetime objects and astropy Time objects are converted to MJD (UTC) days.

  • direction_reference (str, default = 'fk5') – Direction reference frame: 'fk5' (equinox J2000), 'fk4' (equinox B1950), 'icrs' or 'galactic'.

  • projection (str, default = 'SIN') –

  • spectral_reference (str, default = 'lsrk') – Spectral reference frame: a casacore frame ('LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', 'REST', 'GALACTO', 'LGROUP', 'CMB'), a FITS SPECSYS value ('BARYCENT', …) or a schema observer ('lsrk', 'gcrs', …), in any case. The astropy frames 'icrs', 'hcrs' and 'lsr', which have no casacore equivalent, are accepted too, but images in them cannot be written to CASA or FITS.

Return type:

xarray.Dataset

Raises:
  • TypeError – If time_coords are neither numbers nor times.

  • ValueError – If pol_coords are not in canonical order, or spectral_reference is not a spectral reference frame.

make_empty_lmuv_image(phase_center: list[float] | ndarray, image_size: list[int] | ndarray, sky_image_cell_size: list[float] | ndarray, frequency_coords: list[float] | ndarray, pol_coords: list[float] | ndarray, time_coords: list[float] | ndarray, direction_reference: str = 'fk5', projection: str = 'SIN', spectral_reference: str = 'lsrk', do_sky_coords: bool = True) → Dataset[source]

Create an image xarray.Dataset with only coordinates (no datavariables). The image dimensionality is time, frequency, polarization, l, m, u, v

Parameters:
  • phase_center (array of float, length = 2, units = rad) – Image phase center.

  • image_size (array of int, length = 2) – Number of x and y axis pixels in image.

  • sky_image_cell_size (array of float, length = 2, units = rad) – Cell size of sky image. The cell size of the u,v image will be computed from 1/(image_size * sky_image_cell_size)

  • frequency_coords (list or np.ndarray) – The center frequency in Hz of each image channel.

  • pol_coords (list or np.ndarray) – The polarization label of each image polarization, in canonical (casacore Stokes, Jones matrix) order, for example ["I", "Q", "U", "V"], ["RR", "RL", "LR", "LL"] or ["XX", "YY"].

  • time_coords (float, list, np.ndarray, str, datetime or astropy.time.Time) – The time of each temporal plane: numbers are MJD (UTC) days; datetime64 values, ISO time strings, datetime.datetime objects and astropy Time objects are converted to MJD (UTC) days.

  • direction_reference (str, default = 'fk5') – Direction reference frame: 'fk5' (equinox J2000), 'fk4' (equinox B1950), 'icrs' or 'galactic'.

  • projection (str, default = 'SIN') –

  • spectral_reference (str, default = 'lsrk') – Spectral reference frame: a casacore frame ('LSRK', 'LSRD', 'BARY', 'GEO', 'TOPO', 'REST', 'GALACTO', 'LGROUP', 'CMB'), a FITS SPECSYS value ('BARYCENT', …) or a schema observer ('lsrk', 'gcrs', …), in any case. The astropy frames 'icrs', 'hcrs' and 'lsr', which have no casacore equivalent, are accepted too, but images in them cannot be written to CASA or FITS.

  • do_sky_coords (bool) – If True, compute SkyCoord at each pixel and add spherical (sky) dimensions as non-dimensional coordinates in the returned xr.Dataset.

Return type:

xarray.Dataset

Raises:
  • TypeError – If time_coords are neither numbers nor times.

  • ValueError – If pol_coords are not in canonical order, or spectral_reference is not a spectral reference frame.

To check an image dataset against the schema, use check_image() (see the Image Schema).

ImageXds API

Custom accessor to image dataset additional functionality. Given an image xarray.Dataset, named img_xds, the accessor can be used as img_xds.xr_img (xr for xradio and img for image).

class ImageXds(dataset: Dataset)[source]

Accessor to the Image Dataset.

Registered as xr.Dataset.xr_img without xarray’s accessor cache: every ds.xr_img builds a new accessor that holds ds strongly and is never stored on ds. Chained calls on temporaries (ds.isel(...).xr_img.get_lm_cell_size()) therefore work, and there is no ds -> accessor -> ds reference cycle: a dataset dies by reference counting as soon as its last reference (including any accessor kept by the caller) is dropped. The 2026-08 Frontera memory diagnosis traced ~1.5 GB of cyclic garbage per imaging task to the cycle that xarray’s cached accessors form with a strong back-reference.

add_data_group(new_data_group_name: str, new_data_group: dict | None = None, data_group_dv_shared_with: str = None) → Dataset[source]

Adds a data group to the image Dataset, grouping the given data, weight, flag, etc. variables and field_and_source_xds.

Parameters:
  • new_data_group_name (str) – _description_

  • new_data_group (dict) – _description_, by default Non

  • data_group_dv_shared_with (str, optional) – _description_, by default “base”

Returns:

Image Dataset with the new group added

Return type:

xr.Dataset

add_uv_coordinates() → Dataset[source]

Adds the uv coordinates in wavelengths to the image Dataset.

The u and v coordinates are the aperture plane coordinates conjugate to l and m, in wavelengths (units "lambda", the image schema convention), so they do not depend on frequency.

Returns:

Image Dataset with the uv coordinates added.

Return type:

xr.Dataset

delete_data_variables(variables: list[str]) → Dataset[source]

Delete data variables from the image dataset and all data groups.

The variables are deleted from this dataset in place, and every data group role that refers to one of them is removed. Datasets that share data with this one (e.g. made with isel, sel, copy or sel()) keep their variables and data groups.

Parameters:

variables (list of str) – List of data variable names to delete.

Returns:

ImageXds Dataset with specified data variables deleted.

Return type:

xarray.Dataset

Raises:

ValueError – If a name is not a data variable of the dataset (nothing is deleted then).

get_lm_cell_size()[source]

Get the lm cell size in radians from the image Dataset.

Returns:

The lm cell size in radians.

Return type:

float

get_reference_pixel_indices()[source]

Get the reference pixel indices from the image Dataset. The reference pixel is defined as the pixel where l=0 and m=0 or u=0 and v=0.

The reference pixel does not have to be a pixel of the image: a cutout that does not contain the reference direction has its reference pixel outside the image.

Returns:

The (l, m) or (u, v) indices of the reference pixel: integers when it is a pixel of the image, else its fractional (float) pixel position, extrapolated with the coordinate increment outside the image (negative, or beyond the last pixel).

Return type:

numpy.ndarray

get_uv_in_lambda(frequency: float)[source]

Get the uv coordinates in wavelengths for a specific frequency from the image Dataset.

The units attribute of the u and v coordinates decides the conversion: coordinates already in wavelengths ("lambda" or "wavelengths", the convention of the image schema, the readers, the make_empty_* factories and add_uv_coordinates()) are returned unchanged, and coordinates in a length unit (e.g. "m") are divided by the wavelength c / frequency.

Parameters:

frequency (float) – The frequency in Hz to calculate the uv coordinates in wavelengths. Not used when the coordinates are already in wavelengths.

Returns:

The u and v coordinates in wavelengths.

Return type:

tuple of xarray.DataArray

Raises:

ValueError – If a coordinate has no units or units that are neither wavelengths nor a length.

sel(indexers: Mapping[Any, Any] | None = None, method: str | None = None, tolerance: int | float | Iterable[int | float] | None = None, drop: bool = False, **indexers_kwargs: Any) → Dataset[source]

Select data along dimension(s) by label. Alternative to xarray.Dataset.sel so that a data group can be selected by name by using the data_group_name parameter. For more information on data groups see Data Groups section. See xarray.Dataset.sel for parameter descriptions.

Returns:

xarray Dataset with ImageXds accessors

Return type:

xarray.Dataset

Examples

>>> # Select data group 'robust0.5' and polarization 'XX'.
>>> selected_img_xds = img_xds.xr_img.sel(data_group_name='robust0.5', polarization='XX')