Source code for xarray_custom.dataclasses

"""Module for creating custom DataArray classes.

This module provides functions which help to create a custom DataArray class
with fixed dimensions, datatype, and coordinates. Two functions are available:

- ``dataarrayclass``: Class decorator to construct a custom DataArray class.
- ``coord``: Create a DataArray class for the definition of a coordinate.

Examples:
    To create a custom DataArray class to represent images::

        @dataarrayclass
        class Image:
            \"\"\"DataArray class to represent images.\"\"\"

            accessor = 'img'
            dims = 'x', 'y'
            dtype = float

            x: coord('x', int) = 0
            y: coord('y', int) = 0

            def normalize(self):
                return self / self.max()

    The code style is similar to that of Python's dataclass.
    A DataArray is then created using the class::

        image = Image([[0, 1], [2, 3]], x=[0, 1], y=[0, 1])
        print(image)

        # <xarray.DataArray (x: 2, y: 2)>
        # array([[0., 1.],
        #        [2., 3.]])
        # Coordinates:
        #   * x        (x) int64 0 1
        #   * y        (y) int64 0 1

    Because ``dims``, ``dtype``, and coordinates are pre-defined,
    it is much easier to create a DataArray with given data.
    Custom methods can be used via an accessor::

        normalized = image.img.normalize()
        print(normalized)

        # <xarray.DataArray (x: 2, y: 2)>
        # array([[0.        , 0.33333333],
        #        [0.66666667, 1.        ]])
        # Coordinates:
        #   * x        (x) int64 0 1
        #   * y        (y) int64 0 1

    Like NumPy, several special class methods are available
    to create a DataArray filled with some values::

        ones = Image.ones((2, 2))
        print(ones)

        # <xarray.DataArray (x: 2, y: 2)>
        # array([[1., 1.],
        #        [1., 1.]])
        # Coordinates:
        #   * x        (x) int64 0 0
        #   * y        (y) int64 0 0

    Inheriting a custom DataArray class is possible to
    create a derivative DataArray class::

        class WeightedImage(Image):
            accessor = 'wimg'
            w: coord(('x', 'y'), float) = 1.0

        zeros = Weightedimage.zeros((2, 2))
        print(zeros)

        # <xarray.DataArray (x: 2, y: 2)>
        # array([[1., 1.],
        #        [1., 1.]])
        # Coordinates:
        #   * x        (x) int64 0 0
        #   * y        (y) int64 0 0
        #     w        (x, y) float64 1.0 1.0 1.0 1.0

"""
__all__ = ["coord", "dataarrayclass"]


# standard library
from typing import Optional


# dependencies
from .bases import DataArrayClassBase
from .typing import Dims, Dtype


# main functions
[docs]def coord( dims: Optional[Dims] = None, dtype: Optional[Dtype] = None, desc: Optional[str] = None, **_ ) -> type: """Create a DataArray class for the definition of a coordinate. Args: dims: Dimensions of the coordinate. dtype: Datatype of the coordinate. Default is ``None``, which means that an input of any datatype is accepted. desc: Short description of the coordinate. Returns: DataArray class for the coordinate. """ if dims is None: dims = () if desc is None: namespace = dict(dims=dims, dtype=dtype) else: namespace = dict(dims=dims, dtype=dtype, desc=desc) return type("Coord", (DataArrayClassBase,), namespace)
[docs]def dataarrayclass(cls: type) -> type: """Class decorator to construct a custom DataArray class. A class can define properties of DataArray to be created. The following class variables are accepted (see examples). - ``dims`` (str or tuple of str): Name(s) of dimension(s). - ``dtype`` (str or type): Datatype of DataArray. - ``desc`` (str): Short description of DataArray. Users can alternatively define it by a docstring (``__doc__``). - ``accessor`` (str): Name of accessor (if necessary). The coordinates of DataArray can also be defined as class variables using the ``coord`` function (see examples). Finally users can define custom instance methods which can be used by an accessor whose name is defined by ``accessor``. Args: cls: Class to be decorated. Returns: Decorated class as a DataArray class. Examples: To create a custom DataArray class to represent images:: @dataarrayclass class Image: \"\"\"DataArray class to represent images.\"\"\" accessor = 'img' dims = 'x', 'y' dtype = float x: coord('x', int) = 0 y: coord('y', int) = 0 def normalize(self): return self / self.max() """ return type(cls.__name__, (DataArrayClassBase,), cls.__dict__.copy())