<a id="complex"></a>

# Complex Numbers

Xarray leverages NumPy to seamlessly handle complex numbers in [`DataArray`](../generated/xarray.DataArray.html.md#xarray.DataArray) and [`Dataset`](../generated/xarray.Dataset.html.md#xarray.Dataset) objects.

In the examples below, we are using a DataArray named `da` with complex elements (of $\mathbb{C}$ ):

```ipython3
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 [numpy.abs](https://numpy.org/doc/stable/reference/generated/numpy.absolute.html) or [numpy.angle](https://numpy.org/doc/stable/reference/generated/numpy.angle.html) work directly.

```ipython3
da.real
```

```ipython3
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 [netCDF](io.html.md#io-netcdf)) is supported via [`to_netcdf()`](../generated/xarray.DataArray.to_netcdf.html.md#xarray.DataArray.to_netcdf) using specific backend engines that handle complex types:

### h5netcdf

This requires the [h5netcdf](https://h5netcdf.org) library to be installed.

```ipython3
complex_nums_h5_filename = "complex_nums_h5.nc"
```

```ipython3
# write the data to disk
da.to_netcdf(complex_nums_h5_filename, engine="h5netcdf")
# read the file back into memory
ds_h5 = xr.open_dataset(complex_nums_h5_filename, engine="h5netcdf")
# check the dtype
ds_h5[da.name].dtype
```

### netcdf4

Requires the [netcdf4-python (>= 1.7.1)](https://github.com/Unidata/netcdf4-python) library and you have to enable `auto_complex=True`.

```ipython3
complex_nums_nc4_filename = "complex_nums_nc4.nc"
```

```ipython3
# write the data to disk
da.to_netcdf(complex_nums_nc4_filename, engine="netcdf4", auto_complex=True)
# read the file back into memory
ds_nc4 = xr.open_dataset(
    complex_nums_nc4_filename, 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:

```ipython3
complex_manual_filename = "complex_manual.nc"
```

```ipython3
# 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_filename, engine="scipy")  # Example

# Read data from file
ds = xr.open_dataset(complex_manual_filename, 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.

## See also

- [netCDF](io.html.md#io-netcdf) — full NetCDF I/O guide
- [NumPy complex numbers](https://numpy.org/doc/stable/user/basics.types.html#complex)
