diff --git a/doc/user-guide/complex-numbers.rst b/doc/user-guide/complex-numbers.rst new file mode 100644 index 00000000000..e62b9d6f8d8 --- /dev/null +++ b/doc/user-guide/complex-numbers.rst @@ -0,0 +1,124 @@ +.. currentmodule:: xarray + +.. _complex: + +Complex Numbers +=============== + +Xarray leverages NumPy to seamlessly handle complex numbers in :py:class:`~xarray.DataArray` and :py:class:`~xarray.Dataset` objects. + +In the examples below, we are using a DataArray named ``da`` with complex elements (of :math:`\mathbb{C}`): + +.. ipython:: python + + import xarray as xr + import numpy as np + + data = np.array([[1 + 2j, 3 + 4j], [5 + 6j, 7 + 8j]]) + da = xr.DataArray( + data, + dims=["x", "y"], + coords={"x": ["a", "b"], "y": [1, 2]}, + name="complex_nums", + ) + + +Operations on Complex Data +-------------------------- +You can access real and imaginary components using the ``.real`` and ``.imag`` attributes. Most NumPy universal functions (ufuncs) like :py:doc:`numpy.abs ` or :py:doc:`numpy.angle ` work directly. + +.. ipython:: python + + da.real + np.abs(da) + +.. note:: + Like NumPy, ``.real`` and ``.imag`` typically return *views*, not copies, of the original data. + + +Reading and Writing Complex Data +-------------------------------- + +Writing complex data to NetCDF files (see :ref:`io.netcdf`) is supported via :py:meth:`~xarray.DataArray.to_netcdf` using specific backend engines that handle complex types: + + +.. tab:: h5netcdf + + This requires the `h5netcdf `_ library to be installed. + + .. ipython:: python + :okwarning: + + # write the data to disk + da.to_netcdf("complex_nums_h5.nc", engine="h5netcdf") + # read the file back into memory + ds_h5 = xr.open_dataset("complex_nums_h5.nc", engine="h5netcdf") + # check the dtype + ds_h5[da.name].dtype + + +.. tab:: netcdf4 + + Requires the `netcdf4-python (>= 1.7.1) `_ library and you have to enable ``auto_complex=True``. + + .. ipython:: python + :okwarning: + + # write the data to disk + da.to_netcdf("complex_nums_nc4.nc", engine="netcdf4", auto_complex=True) + # read the file back into memory + ds_nc4 = xr.open_dataset( + "complex_nums_nc4.nc", engine="netcdf4", auto_complex=True + ) + # check the dtype + ds_nc4[da.name].dtype + + +.. warning:: + The ``scipy`` engine only supports NetCDF V3 and does *not* support complex arrays; writing with ``engine="scipy"`` raises a ``TypeError``. + + +Alternative: Manual Handling +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If direct writing is not supported (e.g., targeting NetCDF3), you can manually +split the complex array into separate real and imaginary variables before saving: + +.. ipython:: python + + # Write data to file + ds_manual = xr.Dataset( + { + f"{da.name}_real": da.real, + f"{da.name}_imag": da.imag, + } + ) + ds_manual.to_netcdf("complex_manual.nc", engine="scipy") # Example + + # Read data from file + ds = xr.open_dataset("complex_manual.nc", engine="scipy") + reconstructed = ds[f"{da.name}_real"] + 1j * ds[f"{da.name}_imag"] + +Recommendations +^^^^^^^^^^^^^^^ + +- Use ``engine="netcdf4"`` with ``auto_complex=True`` for full compliance and ease. +- Use ``h5netcdf`` for HDF5-based storage when interoperability with HDF5 is desired. +- For maximum legacy support (NetCDF3), manually handle real/imaginary components. + +.. ipython:: python + :suppress: + + # Cleanup + import os + + for f in ["complex_nums_nc4.nc", "complex_nums_h5.nc", "complex_manual.nc"]: + if os.path.exists(f): + os.remove(f) + + + +See also +-------- +- :ref:`io.netcdf` — full NetCDF I/O guide +- `NumPy complex numbers `__ diff --git a/doc/user-guide/index.rst b/doc/user-guide/index.rst index d8c4964457b..92f73c380c6 100644 --- a/doc/user-guide/index.rst +++ b/doc/user-guide/index.rst @@ -27,4 +27,5 @@ examples that describe many common tasks that you can accomplish with xarray. options testing duckarrays + complex-numbers hierarchical-data diff --git a/doc/whats-new.rst b/doc/whats-new.rst index e0a9853ee45..4e6bf5a8bd1 100644 --- a/doc/whats-new.rst +++ b/doc/whats-new.rst @@ -48,6 +48,9 @@ Documentation - Fix references to core classes in docs (:issue:`10195`, :pull:`10207`). By `Mattia Almansi `_. +- Add a dedicated 'Complex Numbers' sections to the User Guide (:issue:`10213`, :pull:`10235`). + By `Andre Wendlinger `_. + Internal Changes ~~~~~~~~~~~~~~~~