xradar is in an early stage of development, please report any issues here!

Accessors#

To extend xarray.DataArray and xarray.Dataset xradar aims to provide accessors which downstream libraries can hook into.

Those accessors are yet to be defined. For starters we could implement purpose-based accessors (like .vis, .kdp or .trafo) on xarray.DataArray level.

To not have to import downstream packages a similar approach to xarray.backends using importlib.metadata.entry_points could be facilitated.

In this notebook the creation of such an accessor is showcased.

[1]:
import numpy as np
import xarray as xr
import xradar as xd
from open_radar_data import DATASETS

Import Data#

Fetch data from open-radar-data repository.

[2]:
filename = DATASETS.fetch("71_20181220_060628.pvol.h5")
Downloading file '71_20181220_060628.pvol.h5' from 'https://github.com/openradar/open-radar-data/raw/main/data/71_20181220_060628.pvol.h5' to '/home/docs/.cache/open-radar-data'.

Open data#

[3]:
ds = xr.open_dataset(filename, group="sweep_0", engine="odim")
display(ds.DBZH.values)
array([[ nan,  0. , 13. , ...,  nan,  nan,  nan],
       [ nan,  1.5, 13.5, ...,  nan,  nan,  nan],
       [ nan,  1.5, 11.5, ...,  nan,  nan,  nan],
       ...,
       [ nan,  1.5, 11.5, ...,  nan,  nan,  nan],
       [ nan,  1.5,  6. , ...,  nan,  nan,  nan],
       [ nan,  6. , 12.5, ...,  nan,  nan,  nan]], dtype=float32)

Plot DBZH#

[4]:
ds.DBZH.plot()
Matplotlib is building the font cache; this may take a moment.
[4]:
<matplotlib.collections.QuadMesh at 0x7f6950fe8410>
../_images/notebooks_Accessors_8_2.png

Define two example functions#

Functions copied verbatim from wradlib.

[5]:
def _decibel(x):
    """Calculates the decibel representation of the input values

    :math:`dBZ=10 \\cdot \\log_{10} z`

    Parameters
    ----------
    x : float or :class:`numpy:numpy.ndarray`
        (must not be <= 0.)

    Examples
    --------
    >>> from wradlib.trafo import decibel
    >>> print(decibel(100.))
    20.0
    """
    return 10.0 * np.log10(x)


def _idecibel(x):
    """Calculates the inverse of input decibel values

    :math:`z=10^{x \\over 10}`

    Parameters
    ----------
    x : float or :class:`numpy:numpy.ndarray`

    Examples
    --------
    >>> from wradlib.trafo import idecibel
    >>> print(idecibel(10.))
    10.0

    """
    return 10.0 ** (x / 10.0)

Function dictionaries#

To show the import of the functions, we put them in different dictionaries as we would get them via entry_points.

This is what the downstream libraries would have to provide.

[6]:
package_1_func = {"trafo": {"decibel": _decibel}}
package_2_func = {"trafo": {"idecibel": _idecibel}}

xradar internal functionality#

This is how xradar would need to treat that input data.

[7]:
downstream_functions = [package_1_func, package_2_func]
xradar_accessors = ["trafo"]
[8]:
package_functions = {}
for accessor in xradar_accessors:
    package_functions[accessor] = {}
    for dfuncs in downstream_functions:
        package_functions[accessor].update(dfuncs[accessor])
print(package_functions)
{'trafo': {'decibel': <function _decibel at 0x7f6950bbaac0>, 'idecibel': <function _idecibel at 0x7f6950bbab60>}}

Create and register accessor#

We bundle the different steps into one function, create_xradar_dataarray_accessor.

[9]:
for accessor in xradar_accessors:
    xd.accessors.create_xradar_dataarray_accessor(accessor, package_functions[accessor])

Convert DBZH to linear and plot#

[10]:
z = ds.DBZH.trafo.idecibel()
z.plot()
[10]:
<matplotlib.collections.QuadMesh at 0x7f695106fb90>
../_images/notebooks_Accessors_19_1.png

Convert z to decibel and plot()#

[11]:
dbz = z.trafo.decibel()
display(dbz)
<xarray.DataArray 'DBZH' (azimuth: 360, range: 1200)> Size: 2MB
array([[      nan,  0.      , 13.      , ...,       nan,       nan,
              nan],
       [      nan,  1.5     , 13.500002, ...,       nan,       nan,
              nan],
       [      nan,  1.5     , 11.500001, ...,       nan,       nan,
              nan],
       ...,
       [      nan,  1.5     , 11.500001, ...,       nan,       nan,
              nan],
       [      nan,  1.5     ,  6.000001, ...,       nan,       nan,
              nan],
       [      nan,  6.000001, 12.500001, ...,       nan,       nan,
              nan]], dtype=float32)
Coordinates:
    elevation  (azimuth) float32 1kB ...
    time       (azimuth) datetime64[ns] 3kB ...
  * range      (range) float32 5kB 125.0 375.0 625.0 ... 2.996e+05 2.999e+05
    longitude  float64 8B ...
    latitude   float64 8B ...
    altitude   float64 8B ...
  * azimuth    (azimuth) float32 1kB 0.5 1.5 2.5 3.5 ... 356.5 357.5 358.5 359.5
[12]:
dbz.plot()
[12]:
<matplotlib.collections.QuadMesh at 0x7f69504679d0>
../_images/notebooks_Accessors_22_1.png