NEXRAD Level 2#

[1]:
import cmweather  # noqa
import xarray as xr
from open_radar_data import DATASETS

import xradar as xd

Download#

Fetching NEXRAD Level2 radar data file from open-radar-data repository.

[2]:
filename = "../../../../Downloads/KDMX20200810_154746_V06"
[3]:
filename = DATASETS.fetch("KATX20130717_195021_V06")
Downloading file 'KATX20130717_195021_V06' from 'https://github.com/openradar/open-radar-data/raw/main/data/KATX20130717_195021_V06' to '/home/docs/.cache/open-radar-data'.

xr.open_dataset#

Making use of the xarray nexradlevel2 backend. We also need to provide the group. Note, that we are using CfRadial2 group access pattern.

[4]:
ds = xr.open_dataset(filename, group="sweep_0", engine="nexradlevel2")
display(ds)
<xarray.Dataset> Size: 42MB
Dimensions:            (azimuth: 720, range: 1832)
Coordinates:
    elevation          (azimuth) float64 6kB ...
    time               (azimuth) datetime64[ns] 6kB ...
  * range              (range) float32 7kB 2.125e+03 2.375e+03 ... 4.599e+05
    longitude          float64 8B ...
    latitude           float64 8B ...
    altitude           int64 8B ...
  * azimuth            (azimuth) float64 6kB 0.2582 0.7526 1.272 ... 359.3 359.8
Data variables:
    DBZH               (azimuth, range) float64 11MB ...
    ZDR                (azimuth, range) float64 11MB ...
    PHIDP              (azimuth, range) float64 11MB ...
    RHOHV              (azimuth, range) float64 11MB ...
    sweep_mode         <U20 80B ...
    sweep_number       int64 8B ...
    prt_mode           <U7 28B ...
    follow_mode        <U7 28B ...
    sweep_fixed_angle  float64 8B ...
Attributes:
    instrument_name:  KATX
[5]:
ds
[5]:
<xarray.Dataset> Size: 42MB
Dimensions:            (azimuth: 720, range: 1832)
Coordinates:
    elevation          (azimuth) float64 6kB ...
    time               (azimuth) datetime64[ns] 6kB ...
  * range              (range) float32 7kB 2.125e+03 2.375e+03 ... 4.599e+05
    longitude          float64 8B ...
    latitude           float64 8B ...
    altitude           int64 8B ...
  * azimuth            (azimuth) float64 6kB 0.2582 0.7526 1.272 ... 359.3 359.8
Data variables:
    DBZH               (azimuth, range) float64 11MB ...
    ZDR                (azimuth, range) float64 11MB ...
    PHIDP              (azimuth, range) float64 11MB ...
    RHOHV              (azimuth, range) float64 11MB ...
    sweep_mode         <U20 80B ...
    sweep_number       int64 8B ...
    prt_mode           <U7 28B ...
    follow_mode        <U7 28B ...
    sweep_fixed_angle  float64 8B ...
Attributes:
    instrument_name:  KATX
[6]:
import numpy as np

np.testing.assert_almost_equal(ds.sweep_fixed_angle.values, 0.4833984)

Plot Time vs. Azimuth#

[7]:
ds.azimuth.plot()
[7]:
[<matplotlib.lines.Line2D at 0x7ff655a43650>]
../_images/notebooks_NexradLevel2_10_1.png

Plot Range vs. Time#

We need to sort by time and specify the y-coordinate.

[8]:
ds.DBZH.sortby("time").plot(y="time", cmap="HomeyerRainbow")
[8]:
<matplotlib.collections.QuadMesh at 0x7ff655521190>
../_images/notebooks_NexradLevel2_12_1.png

Plot Range vs. Azimuth#

[9]:
ds.DBZH.plot(cmap="HomeyerRainbow")
[9]:
<matplotlib.collections.QuadMesh at 0x7ff64d2f7750>
../_images/notebooks_NexradLevel2_14_1.png

backend_kwargs#

Beside first_dim there are several additional backend_kwargs for the nexradlevel2 backend, which handle different aspects of angle alignment. This comes into play, when azimuth and/or elevation arrays are not evenly spacend and other issues.

[10]:
help(xd.io.NexradLevel2BackendEntrypoint)
Help on class NexradLevel2BackendEntrypoint in module xradar.io.backends.nexrad_level2:

class NexradLevel2BackendEntrypoint(xarray.backends.common.BackendEntrypoint)
 |  Xarray BackendEntrypoint for NEXRAD Level2 Data
 |
 |  Method resolution order:
 |      NexradLevel2BackendEntrypoint
 |      xarray.backends.common.BackendEntrypoint
 |      builtins.object
 |
 |  Methods defined here:
 |
 |  open_dataset(self, filename_or_obj, *, mask_and_scale=True, decode_times=True, concat_characters=True, decode_coords=True, drop_variables=None, use_cftime=None, decode_timedelta=None, group=None, first_dim='auto', reindex_angle=False, fix_second_angle=False, site_coords=True, optional=True)
 |      Backend open_dataset method used by Xarray in :py:func:`~xarray.open_dataset`.
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  __annotations__ = {}
 |
 |  description = 'Open NEXRAD Level2 files in Xarray'
 |
 |  open_dataset_parameters = ('filename_or_obj', 'mask_and_scale', 'decod...
 |
 |  url = 'tbd'
 |
 |  ----------------------------------------------------------------------
 |  Methods inherited from xarray.backends.common.BackendEntrypoint:
 |
 |  __repr__(self) -> 'str'
 |      Return repr(self).
 |
 |  guess_can_open(self, filename_or_obj: 'str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore') -> 'bool'
 |      Backend open_dataset method used by Xarray in :py:func:`~xarray.open_dataset`.
 |
 |  open_datatree(self, filename_or_obj: 'str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore', **kwargs: 'Any') -> 'DataTree'
 |      Backend open_datatree method used by Xarray in :py:func:`~xarray.open_datatree`.
 |
 |  open_groups_as_dict(self, filename_or_obj: 'str | os.PathLike[Any] | BufferedIOBase | AbstractDataStore', **kwargs: 'Any') -> 'dict[str, Dataset]'
 |      Opens a dictionary mapping from group names to Datasets.
 |
 |      Called by :py:func:`~xarray.open_groups`.
 |      This function exists to provide a universal way to open all groups in a file,
 |      before applying any additional consistency checks or requirements necessary
 |      to create a `DataTree` object (typically done using :py:meth:`~xarray.DataTree.from_dict`).
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from xarray.backends.common.BackendEntrypoint:
 |
 |  __dict__
 |      dictionary for instance variables
 |
 |  __weakref__
 |      list of weak references to the object

[11]:
ds = xr.open_dataset(filename, group="sweep_0", engine="nexradlevel2", first_dim="time")
display(ds)
<xarray.Dataset> Size: 42MB
Dimensions:            (time: 720, range: 1832)
Coordinates:
    elevation          (time) float64 6kB ...
  * time               (time) datetime64[ns] 6kB 2013-07-17T19:50:21.652000 ....
  * range              (range) float32 7kB 2.125e+03 2.375e+03 ... 4.599e+05
    longitude          float64 8B ...
    latitude           float64 8B ...
    altitude           int64 8B ...
    azimuth            (time) float64 6kB ...
Data variables:
    DBZH               (time, range) float64 11MB ...
    ZDR                (time, range) float64 11MB ...
    PHIDP              (time, range) float64 11MB ...
    RHOHV              (time, range) float64 11MB ...
    sweep_mode         <U20 80B ...
    sweep_number       int64 8B ...
    prt_mode           <U7 28B ...
    follow_mode        <U7 28B ...
    sweep_fixed_angle  float64 8B ...
Attributes:
    instrument_name:  KATX

open_nexradlevel2_datatree#

The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list.

[12]:
help(xd.io.open_nexradlevel2_datatree)
Help on function open_nexradlevel2_datatree in module xradar.io.backends.nexrad_level2:

open_nexradlevel2_datatree(filename_or_obj, **kwargs)
    Open NEXRAD Level2 dataset as :py:class:`datatree.DataTree`.

    Parameters
    ----------
    filename_or_obj : str, Path, file-like or DataStore
        Strings and Path objects are interpreted as a path to a local or remote
        radar file

    Keyword Arguments
    -----------------
    sweep : int, list of int, optional
        Sweep number(s) to extract, default to first sweep. If None, all sweeps are
        extracted into a list.
    first_dim : str
        Can be ``time`` or ``auto`` first dimension. If set to ``auto``,
        first dimension will be either ``azimuth`` or ``elevation`` depending on
        type of sweep. Defaults to ``auto``.
    reindex_angle : bool or dict
        Defaults to False, no reindexing. Given dict should contain the kwargs to
        reindex_angle. Only invoked if `decode_coord=True`.
    fix_second_angle : bool
        If True, fixes erroneous second angle data. Defaults to ``False``.
    site_coords : bool
        Attach radar site-coordinates to Dataset, defaults to ``True``.
    kwargs : dict
        Additional kwargs are fed to :py:func:`xarray.open_dataset`.

    Returns
    -------
    dtree: datatree.DataTree
        DataTree

[13]:
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=4)
display(dtree)
<xarray.DatasetView> Size: 232B
Dimensions:              ()
Data variables:
    volume_number        int64 8B 0
    platform_type        <U5 20B 'fixed'
    instrument_type      <U5 20B 'radar'
    time_coverage_start  <U20 80B '2013-07-17T19:51:38Z'
    time_coverage_end    <U20 80B '2013-07-17T19:52:00Z'
    longitude            float64 8B -122.5
    altitude             int64 8B 195
    latitude             float64 8B 48.19
Attributes:
    Conventions:      None
    instrument_name:  KATX
    version:          None
    title:            None
    institution:      None
    references:       None
    source:           None
    history:          None
    comment:          im/exported using xradar

Plot Sweep Range vs. Time#

[14]:
dtree["sweep_0"].ds.DBZH.sortby("time").plot(y="time", cmap="HomeyerRainbow")
[14]:
<matplotlib.collections.QuadMesh at 0x7ff6391f3e90>
../_images/notebooks_NexradLevel2_22_1.png

Plot Sweep Range vs. Azimuth#

[15]:
dtree["sweep_0"].ds.DBZH.plot(cmap="HomeyerRainbow")
[15]:
<matplotlib.collections.QuadMesh at 0x7ff6392c4b50>
../_images/notebooks_NexradLevel2_24_1.png
[16]:
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep="sweep_8")
display(dtree)
<xarray.DatasetView> Size: 232B
Dimensions:              ()
Data variables:
    volume_number        int64 8B 0
    platform_type        <U5 20B 'fixed'
    instrument_type      <U5 20B 'radar'
    time_coverage_start  <U20 80B '2013-07-17T19:53:05Z'
    time_coverage_end    <U20 80B '2013-07-17T19:53:25Z'
    longitude            float64 8B -122.5
    altitude             int64 8B 195
    latitude             float64 8B 48.19
Attributes:
    Conventions:      None
    instrument_name:  KATX
    version:          None
    title:            None
    institution:      None
    references:       None
    source:           None
    history:          None
    comment:          im/exported using xradar
[17]:
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=[0, 1, 8])
display(dtree)
<xarray.DatasetView> Size: 232B
Dimensions:              ()
Data variables:
    volume_number        int64 8B 0
    platform_type        <U5 20B 'fixed'
    instrument_type      <U5 20B 'radar'
    time_coverage_start  <U20 80B '2013-07-17T19:50:21Z'
    time_coverage_end    <U20 80B '2013-07-17T19:53:25Z'
    longitude            float64 8B -122.5
    altitude             int64 8B 195
    latitude             float64 8B 48.19
Attributes:
    Conventions:      None
    instrument_name:  KATX
    version:          None
    title:            None
    institution:      None
    references:       None
    source:           None
    history:          None
    comment:          im/exported using xradar
[18]:
dtree["sweep_0"]["sweep_fixed_angle"].values
[18]:
array(0.48339844)
[19]:
dtree["sweep_1"]["sweep_fixed_angle"].values
[19]:
array(0.48339844)
[20]:
dtree = xd.io.open_nexradlevel2_datatree(
    filename,
)
display(dtree)
<xarray.DatasetView> Size: 232B
Dimensions:              ()
Data variables:
    volume_number        int64 8B 0
    platform_type        <U5 20B 'fixed'
    instrument_type      <U5 20B 'radar'
    time_coverage_start  <U20 80B '2013-07-17T19:50:21Z'
    time_coverage_end    <U20 80B '2013-07-17T19:55:11Z'
    longitude            float64 8B -122.5
    altitude             int64 8B 195
    latitude             float64 8B 48.19
Attributes:
    Conventions:      None
    instrument_name:  KATX
    version:          None
    title:            None
    institution:      None
    references:       None
    source:           None
    history:          None
    comment:          im/exported using xradar
[21]:
dtree["sweep_1"]
[21]:
<xarray.DatasetView> Size: 21MB
Dimensions:            (azimuth: 720, range: 1192)
Coordinates:
    elevation          (azimuth) float64 6kB ...
    time               (azimuth) datetime64[ns] 6kB 2013-07-17T19:50:41.34099...
  * range              (range) float32 5kB 2.125e+03 2.375e+03 ... 2.999e+05
    longitude          float64 8B ...
    latitude           float64 8B ...
    altitude           int64 8B ...
  * azimuth            (azimuth) float64 6kB 0.2499 0.7938 1.252 ... 359.2 359.8
Data variables:
    DBZH               (azimuth, range) float64 7MB ...
    VRADH              (azimuth, range) float64 7MB ...
    WRADH              (azimuth, range) float64 7MB ...
    sweep_mode         <U20 80B ...
    sweep_number       int64 8B ...
    prt_mode           <U7 28B ...
    follow_mode        <U7 28B ...
    sweep_fixed_angle  float64 8B ...
Attributes:
    instrument_name:  KATX
[ ]: