# xarray-units
[![Release](https://img.shields.io/pypi/v/xarray-units?label=Release&color=cornflowerblue&style=flat-square)](https://pypi.org/project/xarray-units/)
[![Python](https://img.shields.io/pypi/pyversions/xarray-units?label=Python&color=cornflowerblue&style=flat-square)](https://pypi.org/project/xarray-units/)
[![Downloads](https://img.shields.io/pypi/dm/xarray-units?label=Downloads&color=cornflowerblue&style=flat-square)](https://pepy.tech/project/xarray-units)
[![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.10354517-cornflowerblue?style=flat-square)](https://doi.org/10.5281/zenodo.10354517)
[![Tests](https://img.shields.io/github/actions/workflow/status/astropenguin/xarray-units/tests.yaml?label=Tests&style=flat-square)](https://github.com/astropenguin/xarray-units/actions)
xarray extension for handling units
## Overview
xarray-units is an import-only package that provides a [xarray](https://xarray.dev) DataArray accessor `.units` for handling units such as converting units and numeric operations considering units.
[Astropy](https://www.astropy.org) is used as a backend.
Unlike similar implementations, xarray-units does not use a special data type to handle units, but uses the original data type in a DataArray.
This allows to continue to use powerful features such as parallel and lazy processing with [Dask](https://www.dask.org) and/or user-defined DataArray subclasses.
## Installation
```shell
pip install xarray-units==0.5.0
```
## Basic usages
Suppose the following imports will be commonly used in the examples:
```python
import xarray as xr
import xarray_units
```
### Setting and unsetting units
xarray-units sets units in DataArray attributes (`.attrs`) with the name `"units"`:
```python
da_km = xr.DataArray([1, 2, 3]).units.set("km")
print(da_km)
```
```
<xarray.DataArray (dim_0: 3)>
array([1, 2, 3])
Dimensions without coordinates: dim_0
Attributes:
units: km
```
And the units can also be unset (deleted):
```python
da = da_km.units.unset()
print(da)
```
```
<xarray.DataArray (dim_0: 3)>
array([1, 2, 3])
Dimensions without coordinates: dim_0
```
> [!NOTE]
> These are equivalent to manually un/setting the units in the DataArray attributes, but the `units` accessor also check that the units are valid when setting.
### Converting units to others
xarray-units converts a DataArray with units to other units:
```python
da_km = xr.DataArray([1, 2, 3]).units.set("km")
da_m = da_km.units.to("m")
print(da_m)
```
```
<xarray.DataArray (dim_0: 3)>
array([1000., 2000., 3000.])
Dimensions without coordinates: dim_0
Attributes:
units: m
```
Astropy [equivalencies](https://docs.astropy.org/en/stable/units/equivalencies.html) can also be used for equivalences between different units:
```python
from astropy.units import spectral
da_mm = xr.DataArray([1, 2, 3]).units.set("mm")
da_GHz = da_mm.units.to("GHz", spectral())
print(da_GHz)
```
```
<xarray.DataArray (dim_1: 3)>
array([299.792458 , 149.896229 , 99.93081933])
Dimensions without coordinates: dim_0
Attributes:
units: GHz
```
> [!TIP]
> There exist other accessor methods (e.g. `decompose`, `like`) for converting units.
> See [the package guide](https://astropenguin.github.io/xarray-units/_apidoc/xarray_units.accessor.html) for more details.
### Numeric operations considering units
xarray-units performs numerical operations considering units when the `units` accessor is attached to the DataArray on the left side of the operator:
```python
da_m = xr.DataArray([1000, 2000, 3000]).units.set("m")
da_km = xr.DataArray([1, 2, 3]).units.set("km")
da_sum_m = da_m.units + da_km
da_sum_km = da_km.units + da_m
print(da_sum_m)
print(da_sum_km)
```
```
<xarray.DataArray (dim_0: 3)>
array([2000., 4000., 6000.])
Dimensions without coordinates: dim_0
Attributes:
units: m
<xarray.DataArray (dim_0: 3)>
array([2., 4., 6.])
Dimensions without coordinates: dim_0
Attributes:
units: km
```
The units of the DataArray after the operation follows those of the DataArray with the `units` accessor.
The resulting data values will be therefore different depending on the order of the operation.
They are, of course, equal when considering units:
```python
da_eq = (da_sum_m.units == da_sum_km)
print(da_eq)
```
```
<xarray.DataArray (dim_0: 3)>
array([ True, True, True])
Dimensions without coordinates: dim_0
```
> [!IMPORTANT]
> Because this feature is accessor-based, units are only considered for the operation right after the `units` accessor.
> See [method and operation chains](#method-and-operation-chains) for performing multiple operations at once.
> [!TIP]
> There exist accessor methods corresponding to each operator (e.g. `add` → `+`, `eq` → `==`).
> See [the package guide](https://astropenguin.github.io/xarray-units/_apidoc/xarray_units.accessor.html) for more details.
### Formatting units
xarray-units converts units to [various string formats](https://docs.astropy.org/en/stable/units/format.html):
```python
da = xr.DataArray([1, 2, 3]).units.set("m / s^2")
da_console = da.units.format("console")
da_latex = da.units.format("latex")
print(da_console)
print(da_latex)
```
```
<xarray.DataArray (dim_0: 3)>
array([1, 2, 3])
Dimensions without coordinates: dim_0
Attributes:
units: m s^-2
<xarray.DataArray (dim_0: 3)>
array([1, 2, 3])
Dimensions without coordinates: dim_0
Attributes:
units: $\mathrm{\frac{m}{s^{2}}}$
```
This is useful, for example, when plotting a DataArray:
```python
da.units.format("latex").plot()
```
> [!NOTE]
> By default, the units of the DataArray coordinates will also be formatted.
## Advanced usages
### Handling units of coordinates
The `units` accessor has an option for handling units of DataArray coordinates.
For example, the following code will create a DataArray with `x` and `y` coordinates in units of meters:
```python
da_m = xr.DataArray([[1, 2], [3, 4]], dims=["x", "y"]).units.set("deg_C")
da_m = da_m.assign_coords(
x=xr.DataArray([1000, 2000], dims="x").units.set("m"),
y=xr.DataArray([3000, 4000], dims="y").units.set("m"),
)
print(da_m.x)
print(da_m.y)
```
```
<xarray.DataArray 'x' (x: 2)>
array([1000, 2000])
Coordinates:
* x (x) int64 1000 2000
Attributes:
units: m
<xarray.DataArray 'y' (y: 2)>
array([3000, 4000])
Coordinates:
* y (y) int64 3000 4000
Attributes:
units: m
```
To handling the units of the DataArray coordinates, use an option `of` for specifying them:
```python
da_km = da_m.units(of=["x", "y"]).to("km")
print(da_km.x)
print(da_km.y)
```
```
<xarray.DataArray 'x' (x: 2)>
array([1., 2.])
Coordinates:
* x (x) float64 1.0 2.0
Attributes:
units: km
<xarray.DataArray 'y' (y: 2)>
array([3., 4.])
Coordinates:
* y (y) float64 3.0 4.0
Attributes:
units: km
```
where `of` accepts the name(s) of the coordinate(s).
### Method and operation chains
The `units` accessor has an option `chain` for chaining methods or operations while considering units:
```python
da_m = xr.DataArray([1, 2, 3]).units.set("m")
da_s = xr.DataArray([1, 2, 3]).units.set("s")
da_a = da_m.units(chain=2) / da_s / da_s
print(da_a)
```
```
<xarray.DataArray (dim_0: 3)>
array([1. , 0.5 , 0.33333333])
Dimensions without coordinates: dim_0
Attributes:
units: m / s2
```
where `chain` is the number of chained methods or operations.
This is equivalent to nesting the `units` accessors:
```python
(da_m.units / da_s).units / da_s
```
### Use with static type checking
xarray-units provides a special type hint `xarray_units.DataArray` with which type checkers can statically handle the `units ` accessor and its methods:
```python
from xarray_units import DataArray
da: DataArray = xr.DataArray([1, 2, 3]).units.set("km")
```
> [!TIP]
> `xarray_units.DataArray` will be replaced by `xarray.DataArray` at runtime, so it can also be used for creating and subclassing `DataArray`.
### Use without the units accessor
xarray-units provides a function `xarray_units.units` that returns the `units` accessor of a DataArray.
The following two codes are therefore equivalent:
```python
xr.DataArray([1, 2, 3]).units.set("km")
```
```python
from xarray_units import units
units(xr.DataArray([1, 2, 3])).set("km")
```
Raw data
{
"_id": null,
"home_page": "https://github.com/astropenguin/xarray-units/",
"name": "xarray-units",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.9,<3.13",
"maintainer_email": "",
"keywords": "xarray,xarray-accessor,xarray-extension,units",
"author": "Akio Taniguchi",
"author_email": "taniguchi@a.phys.nagoya-u.ac.jp",
"download_url": "https://files.pythonhosted.org/packages/06/e3/226f29cc3d8ce5c24393e04ee560245b0155b92b11e1360e0fc97b3daa27/xarray_units-0.5.0.tar.gz",
"platform": null,
"description": "# xarray-units\n\n[![Release](https://img.shields.io/pypi/v/xarray-units?label=Release&color=cornflowerblue&style=flat-square)](https://pypi.org/project/xarray-units/)\n[![Python](https://img.shields.io/pypi/pyversions/xarray-units?label=Python&color=cornflowerblue&style=flat-square)](https://pypi.org/project/xarray-units/)\n[![Downloads](https://img.shields.io/pypi/dm/xarray-units?label=Downloads&color=cornflowerblue&style=flat-square)](https://pepy.tech/project/xarray-units)\n[![DOI](https://img.shields.io/badge/DOI-10.5281/zenodo.10354517-cornflowerblue?style=flat-square)](https://doi.org/10.5281/zenodo.10354517)\n[![Tests](https://img.shields.io/github/actions/workflow/status/astropenguin/xarray-units/tests.yaml?label=Tests&style=flat-square)](https://github.com/astropenguin/xarray-units/actions)\n\nxarray extension for handling units\n\n## Overview\n\nxarray-units is an import-only package that provides a [xarray](https://xarray.dev) DataArray accessor `.units` for handling units such as converting units and numeric operations considering units.\n[Astropy](https://www.astropy.org) is used as a backend.\nUnlike similar implementations, xarray-units does not use a special data type to handle units, but uses the original data type in a DataArray.\nThis allows to continue to use powerful features such as parallel and lazy processing with [Dask](https://www.dask.org) and/or user-defined DataArray subclasses.\n\n## Installation\n\n```shell\npip install xarray-units==0.5.0\n```\n\n## Basic usages\n\nSuppose the following imports will be commonly used in the examples:\n\n```python\nimport xarray as xr\nimport xarray_units\n```\n\n### Setting and unsetting units\n\nxarray-units sets units in DataArray attributes (`.attrs`) with the name `\"units\"`:\n\n```python\nda_km = xr.DataArray([1, 2, 3]).units.set(\"km\")\nprint(da_km)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([1, 2, 3])\nDimensions without coordinates: dim_0\nAttributes:\n units: km\n```\n\nAnd the units can also be unset (deleted):\n\n```python\nda = da_km.units.unset()\nprint(da)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([1, 2, 3])\nDimensions without coordinates: dim_0\n```\n\n> [!NOTE]\n> These are equivalent to manually un/setting the units in the DataArray attributes, but the `units` accessor also check that the units are valid when setting.\n\n### Converting units to others\n\nxarray-units converts a DataArray with units to other units:\n\n```python\nda_km = xr.DataArray([1, 2, 3]).units.set(\"km\")\nda_m = da_km.units.to(\"m\")\nprint(da_m)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([1000., 2000., 3000.])\nDimensions without coordinates: dim_0\nAttributes:\n units: m\n```\n\nAstropy [equivalencies](https://docs.astropy.org/en/stable/units/equivalencies.html) can also be used for equivalences between different units:\n\n```python\nfrom astropy.units import spectral\n\nda_mm = xr.DataArray([1, 2, 3]).units.set(\"mm\")\nda_GHz = da_mm.units.to(\"GHz\", spectral())\nprint(da_GHz)\n```\n\n```\n<xarray.DataArray (dim_1: 3)>\narray([299.792458 , 149.896229 , 99.93081933])\nDimensions without coordinates: dim_0\nAttributes:\n units: GHz\n```\n\n> [!TIP]\n> There exist other accessor methods (e.g. `decompose`, `like`) for converting units.\n> See [the package guide](https://astropenguin.github.io/xarray-units/_apidoc/xarray_units.accessor.html) for more details.\n\n### Numeric operations considering units\n\nxarray-units performs numerical operations considering units when the `units` accessor is attached to the DataArray on the left side of the operator:\n\n```python\nda_m = xr.DataArray([1000, 2000, 3000]).units.set(\"m\")\nda_km = xr.DataArray([1, 2, 3]).units.set(\"km\")\n\nda_sum_m = da_m.units + da_km\nda_sum_km = da_km.units + da_m\n\nprint(da_sum_m)\nprint(da_sum_km)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([2000., 4000., 6000.])\nDimensions without coordinates: dim_0\nAttributes:\n units: m\n\n<xarray.DataArray (dim_0: 3)>\narray([2., 4., 6.])\nDimensions without coordinates: dim_0\nAttributes:\n units: km\n```\n\nThe units of the DataArray after the operation follows those of the DataArray with the `units` accessor.\nThe resulting data values will be therefore different depending on the order of the operation.\nThey are, of course, equal when considering units:\n\n```python\nda_eq = (da_sum_m.units == da_sum_km)\nprint(da_eq)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([ True, True, True])\nDimensions without coordinates: dim_0\n```\n\n> [!IMPORTANT]\n> Because this feature is accessor-based, units are only considered for the operation right after the `units` accessor.\n> See [method and operation chains](#method-and-operation-chains) for performing multiple operations at once.\n\n> [!TIP]\n> There exist accessor methods corresponding to each operator (e.g. `add` \u2192 `+`, `eq` \u2192 `==`).\n> See [the package guide](https://astropenguin.github.io/xarray-units/_apidoc/xarray_units.accessor.html) for more details.\n\n### Formatting units\n\nxarray-units converts units to [various string formats](https://docs.astropy.org/en/stable/units/format.html):\n\n```python\nda = xr.DataArray([1, 2, 3]).units.set(\"m / s^2\")\n\nda_console = da.units.format(\"console\")\nda_latex = da.units.format(\"latex\")\n\nprint(da_console)\nprint(da_latex)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([1, 2, 3])\nDimensions without coordinates: dim_0\nAttributes:\n units: m s^-2\n\n<xarray.DataArray (dim_0: 3)>\narray([1, 2, 3])\nDimensions without coordinates: dim_0\nAttributes:\n units: $\\mathrm{\\frac{m}{s^{2}}}$\n```\n\nThis is useful, for example, when plotting a DataArray:\n\n```python\nda.units.format(\"latex\").plot()\n```\n\n> [!NOTE]\n> By default, the units of the DataArray coordinates will also be formatted.\n\n## Advanced usages\n\n### Handling units of coordinates\n\nThe `units` accessor has an option for handling units of DataArray coordinates.\nFor example, the following code will create a DataArray with `x` and `y` coordinates in units of meters:\n\n```python\nda_m = xr.DataArray([[1, 2], [3, 4]], dims=[\"x\", \"y\"]).units.set(\"deg_C\")\nda_m = da_m.assign_coords(\n x=xr.DataArray([1000, 2000], dims=\"x\").units.set(\"m\"),\n y=xr.DataArray([3000, 4000], dims=\"y\").units.set(\"m\"),\n)\nprint(da_m.x)\nprint(da_m.y)\n```\n\n```\n<xarray.DataArray 'x' (x: 2)>\narray([1000, 2000])\nCoordinates:\n * x (x) int64 1000 2000\nAttributes:\n units: m\n\n<xarray.DataArray 'y' (y: 2)>\narray([3000, 4000])\nCoordinates:\n * y (y) int64 3000 4000\nAttributes:\n units: m\n```\n\nTo handling the units of the DataArray coordinates, use an option `of` for specifying them:\n\n```python\nda_km = da_m.units(of=[\"x\", \"y\"]).to(\"km\")\nprint(da_km.x)\nprint(da_km.y)\n```\n\n```\n<xarray.DataArray 'x' (x: 2)>\narray([1., 2.])\nCoordinates:\n * x (x) float64 1.0 2.0\nAttributes:\n units: km\n\n<xarray.DataArray 'y' (y: 2)>\narray([3., 4.])\nCoordinates:\n * y (y) float64 3.0 4.0\nAttributes:\n units: km\n```\n\nwhere `of` accepts the name(s) of the coordinate(s).\n\n### Method and operation chains\n\nThe `units` accessor has an option `chain` for chaining methods or operations while considering units:\n\n```python\nda_m = xr.DataArray([1, 2, 3]).units.set(\"m\")\nda_s = xr.DataArray([1, 2, 3]).units.set(\"s\")\nda_a = da_m.units(chain=2) / da_s / da_s\nprint(da_a)\n```\n\n```\n<xarray.DataArray (dim_0: 3)>\narray([1. , 0.5 , 0.33333333])\nDimensions without coordinates: dim_0\nAttributes:\n units: m / s2\n```\n\nwhere `chain` is the number of chained methods or operations.\nThis is equivalent to nesting the `units` accessors:\n\n```python\n(da_m.units / da_s).units / da_s\n```\n\n### Use with static type checking\n\nxarray-units provides a special type hint `xarray_units.DataArray` with which type checkers can statically handle the `units ` accessor and its methods:\n\n```python\nfrom xarray_units import DataArray\n\nda: DataArray = xr.DataArray([1, 2, 3]).units.set(\"km\")\n```\n\n> [!TIP]\n> `xarray_units.DataArray` will be replaced by `xarray.DataArray` at runtime, so it can also be used for creating and subclassing `DataArray`.\n\n### Use without the units accessor\n\nxarray-units provides a function `xarray_units.units` that returns the `units` accessor of a DataArray.\nThe following two codes are therefore equivalent:\n\n```python\nxr.DataArray([1, 2, 3]).units.set(\"km\")\n```\n\n```python\nfrom xarray_units import units\n\nunits(xr.DataArray([1, 2, 3])).set(\"km\")\n```\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "xarray extension for handling units",
"version": "0.5.0",
"project_urls": {
"Documentation": "https://astropenguin.github.io/xarray-units/",
"Homepage": "https://github.com/astropenguin/xarray-units/"
},
"split_keywords": [
"xarray",
"xarray-accessor",
"xarray-extension",
"units"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d1f47cbd6bf2372e725b1ad07ef9ab6b0fba9d4670cdb14fe65bbab94c8d2235",
"md5": "e4a9520020404039d9797233529bcdfc",
"sha256": "655179f97171f593449901ed7695253234899c4d2e4637ed9ed30765bfe02cd0"
},
"downloads": -1,
"filename": "xarray_units-0.5.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "e4a9520020404039d9797233529bcdfc",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9,<3.13",
"size": 10926,
"upload_time": "2024-02-03T18:55:15",
"upload_time_iso_8601": "2024-02-03T18:55:15.049370Z",
"url": "https://files.pythonhosted.org/packages/d1/f4/7cbd6bf2372e725b1ad07ef9ab6b0fba9d4670cdb14fe65bbab94c8d2235/xarray_units-0.5.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "06e3226f29cc3d8ce5c24393e04ee560245b0155b92b11e1360e0fc97b3daa27",
"md5": "03aabfa67385e0aa322d490c0cc93ef2",
"sha256": "b1d3d95eb7438dc0c8e64c07c6fae6790a9d7e4ecced75b6d5492d48e4c20ffd"
},
"downloads": -1,
"filename": "xarray_units-0.5.0.tar.gz",
"has_sig": false,
"md5_digest": "03aabfa67385e0aa322d490c0cc93ef2",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9,<3.13",
"size": 11147,
"upload_time": "2024-02-03T18:55:16",
"upload_time_iso_8601": "2024-02-03T18:55:16.707019Z",
"url": "https://files.pythonhosted.org/packages/06/e3/226f29cc3d8ce5c24393e04ee560245b0155b92b11e1360e0fc97b3daa27/xarray_units-0.5.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-03 18:55:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "astropenguin",
"github_project": "xarray-units",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "xarray-units"
}