Skip to content

Commit

Permalink
NEXRAD Level2 structured reader (#158)
Browse files Browse the repository at this point in the history
* NEXRAD structured reader

* WIP nexrad

* WIP lint

* WIP lint

* WIP fixture

* WIP lint

* WIP entrypoint

* WIP fix tests

* WIP nexrad bz2 compression

* MNT CI/open-radar-data

* ADD io tests

* fix nexradlevel2 tests

* add NexradLevel2 notebook, docstring, fix tests/moments

* add history.md entry
  • Loading branch information
kmuehlbauer committed Mar 13, 2024
1 parent a854715 commit 56a9ca1
Show file tree
Hide file tree
Showing 16 changed files with 2,436 additions and 12 deletions.
3 changes: 1 addition & 2 deletions ci/notebooktests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
- netCDF4
- notebook
- numpy
- open-radar-data>=0.1.0
- pip
- pyproj
- pytest
Expand All @@ -32,5 +33,3 @@ dependencies:
- arm_pyart
- ffmpeg
- zarr
- pip:
- git+https://github.com/openradar/open-radar-data.git
3 changes: 1 addition & 2 deletions ci/unittests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ dependencies:
- lat_lon_parser
- netCDF4
- numpy
- open-radar-data>=0.1.0
- pip
- pyproj
- pytest
Expand All @@ -25,5 +26,3 @@ dependencies:
- xarray
- xarray-datatree>=0.0.10
- xmltodict
- pip:
- git+https://github.com/openradar/open-radar-data.git
1 change: 1 addition & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* MNT: restructure odim.py/gamic.py, add test_odim.py/test_gamic.py ({pull}`154`) by [@kmuehlbauer](https://github.com/kmuehlbauer).
* MNT: use CODECOV token ({pull}`155`) by [@kmuehlbauer](https://github.com/kmuehlbauer).
* MNT: fix path for notebook coverage ({pull}`157`) by [@kmuehlbauer](https://github.com/kmuehlbauer).
* ADD: NEXRAD Level2 structured reader ({pull}`158`) by [@kmuehlbauer](https://github.com/kmuehlbauer) and [@mgrover1](https://github.com/mgrover1).

## 0.4.3 (2024-02-24)

Expand Down
19 changes: 19 additions & 0 deletions docs/importers.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Currently xradar can import:
- [](#furuno-scn-and-scnx)
- [](#rainbow)
- [](#iris-sigmet)
- [](#nexradlevel2)

## CfRadial1

Expand Down Expand Up @@ -115,3 +116,21 @@ more functions are applied on that {py:class}`xarray:xarray.Dataset`.
With {func}`~xradar.io.backends.iris.open_iris_datatree` all groups (eg. ``1``)
are extracted. From that the ``root`` group is processed. Everything is finally added as
ParentNodes and ChildNodes to a {py:class}`datatree:datatree.DataTree`.


## NexradLevel2

### NexradLevel2BackendEntryPoint

The xarray backend {class}`~xradar.io.backends.nexrad_level2.NexradLevel2BackendEntryPoint`
opens the file with {class}`~xradar.io.backends.nexrad_level2.NexradLevel2Store`. Several
private helper functions are used to conveniently access data and
metadata. Finally, the xarray machinery returns a {py:class}`xarray:xarray.Dataset`
with wanted group (eg. ``0``). Depending on the used backend kwargs several
more functions are applied on that {py:class}`xarray:xarray.Dataset`.

### open_nexradlevel2_datatree

With {func}`~xradar.io.backends.nexrad_level2.open_nexradlevel2_datatree`
all groups (eg. ``1``) are extracted. From that the ``root`` group is processed.
Everything is finally added as ParentNodes and ChildNodes to a {py:class}`datatree:datatree.DataTree`.
1 change: 1 addition & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ notebooks/GAMIC
notebooks/Furuno
notebooks/Rainbow
notebooks/Iris
notebooks/NexradLevel2
notebooks/Read-plot-Sigmet-data-from-AWS
notebooks/plot-ppi
notebooks/angle_reindexing
Expand Down
3 changes: 1 addition & 2 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
- h5py
- lat_lon_parser
- netCDF4
- open-radar-data>=0.1.0
- pyproj
- xarray
- xarray-datatree>=0.0.10
Expand All @@ -29,5 +30,3 @@ dependencies:
- arm_pyart
- ffmpeg
- zarr
- pip:
- git+https://github.com/openradar/open-radar-data.git
271 changes: 271 additions & 0 deletions examples/notebooks/NexradLevel2.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# NEXRAD Level 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"import xarray as xr\n",
"import xradar as xd\n",
"import cmweather\n",
"from open_radar_data import DATASETS"
]
},
{
"cell_type": "markdown",
"id": "2",
"metadata": {},
"source": [
"## Download\n",
"\n",
"Fetching NEXRAD Level2 radar data file from [open-radar-data](https://github.com/openradar/open-radar-data) repository."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3",
"metadata": {},
"outputs": [],
"source": [
"filename = DATASETS.fetch(\"KLBB20160601_150025_V06\")"
]
},
{
"cell_type": "markdown",
"id": "4",
"metadata": {},
"source": [
"## xr.open_dataset\n",
"\n",
"Making use of the xarray `nexradlevel2` backend. We also need to provide the group. Note, that we are using CfRadial2 group access pattern."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5",
"metadata": {},
"outputs": [],
"source": [
"ds = xr.open_dataset(filename, group=\"sweep_0\", engine=\"nexradlevel2\")\n",
"display(ds)"
]
},
{
"cell_type": "markdown",
"id": "6",
"metadata": {},
"source": [
"### Plot Time vs. Azimuth"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7",
"metadata": {},
"outputs": [],
"source": [
"ds.azimuth.plot()"
]
},
{
"cell_type": "markdown",
"id": "8",
"metadata": {},
"source": [
"### Plot Range vs. Time\n",
"\n",
"We need to sort by time and specify the y-coordinate."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9",
"metadata": {},
"outputs": [],
"source": [
"ds.DBZH.sortby(\"time\").plot(y=\"time\", cmap=\"HomeyerRainbow\")"
]
},
{
"cell_type": "markdown",
"id": "10",
"metadata": {},
"source": [
"### Plot Range vs. Azimuth\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11",
"metadata": {},
"outputs": [],
"source": [
"ds.DBZH.plot(cmap=\"HomeyerRainbow\")"
]
},
{
"cell_type": "markdown",
"id": "12",
"metadata": {},
"source": [
"## backend_kwargs\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [],
"source": [
"help(xd.io.NexradLevel2BackendEntrypoint)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"metadata": {},
"outputs": [],
"source": [
"ds = xr.open_dataset(filename, group=\"sweep_0\", engine=\"nexradlevel2\", first_dim=\"time\")\n",
"display(ds)"
]
},
{
"cell_type": "markdown",
"id": "15",
"metadata": {},
"source": [
"## open_nexradlevel2_datatree\n",
"\n",
"The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"metadata": {},
"outputs": [],
"source": [
"help(xd.io.open_nexradlevel2_datatree)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "17",
"metadata": {},
"outputs": [],
"source": [
"dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=4)\n",
"display(dtree)"
]
},
{
"cell_type": "markdown",
"id": "18",
"metadata": {},
"source": [
"### Plot Sweep Range vs. Time"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "19",
"metadata": {},
"outputs": [],
"source": [
"dtree[\"sweep_0\"].ds.DBZH.sortby(\"time\").plot(y=\"time\", cmap=\"HomeyerRainbow\")"
]
},
{
"cell_type": "markdown",
"id": "20",
"metadata": {},
"source": [
"### Plot Sweep Range vs. Azimuth"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "21",
"metadata": {},
"outputs": [],
"source": [
"dtree[\"sweep_0\"].ds.DBZH.plot(cmap=\"HomeyerRainbow\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "22",
"metadata": {},
"outputs": [],
"source": [
"dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=\"sweep_8\")\n",
"display(dtree)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "23",
"metadata": {},
"outputs": [],
"source": [
"dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=[0, 1, 8])\n",
"display(dtree)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "24",
"metadata": {},
"outputs": [],
"source": [
"dtree = xd.io.open_nexradlevel2_datatree(\n",
" filename, sweep=[\"sweep_1\", \"sweep_2\", \"sweep_8\"]\n",
")\n",
"display(dtree)"
]
}
],
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ gamic = "xradar.io.backends:GamicBackendEntrypoint"
iris = "xradar.io.backends:IrisBackendEntrypoint"
odim = "xradar.io.backends:OdimBackendEntrypoint"
rainbow = "xradar.io.backends:RainbowBackendEntrypoint"
nexradlevel2 = "xradar.io.backends:NexradLevel2BackendEntrypoint"


[build-system]
requires = [
Expand Down
Loading

0 comments on commit 56a9ca1

Please sign in to comment.