wradlib logo png

wradlib time series data and quasi vertical profiles


Overview

Within this notebook, we will cover:

  1. Reading radar sweep timeseries data into xarray based RadarVolume

  2. Examination of RadarVolume and Sweep

  3. Calculation of Quasivertical Profiles and Plotting

Prerequisites

Concepts

Importance

Notes

Matplotlib Basics

Helpful

Basic Plotting

Xarray Basics

Helpful

Basic Dataset/DataArray

Xarray Plotting

Helpful

Basic Plotting/Faceting

  • Time to learn: 7.5 minutes


Imports

import glob
import os

import matplotlib.pyplot as plt
import numpy as np
import xarray as xr
from tqdm import tqdm_notebook as tqdm

import wradlib as wrl
/srv/conda/envs/notebook/lib/python3.9/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.8) or chardet (5.2.0)/charset_normalizer (2.0.10) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "

Import Australian Radar Data

It is assumed, that data from IDR71 (Terrey Hills, Sidney) from 20th of December 2018 is used in this notebook.

fglob = "data/hdf5/terrey_*.h5"
idr71 = glob.glob(fglob)
idr71.sort()
print("Files available: {}".format(len(idr71)))
Files available: 40

Single Quasi Vertical Profile (QVP)

odh = wrl.io.open_odim_dataset(idr71[24])
display(odh)
<wradlib.RadarVolume>
Dimension(s): (sweep: 1)
Elevation(s): (32.0)

This example shows how to create a so called QVP. We need to define a function to add a height coordinate for plotting.

def add_height(ds):
    ds = ds.pipe(wrl.georef.georeference_dataset)
    height = ds.z.mean("azimuth")
    ds = ds.assign_coords({"height": (["range"], height.data)})
    return ds

Here we add the height coordinate and calculate the mean over the azimuth using the sweep with the highest available elevation.

swp = odh[0].pipe(add_height)
display(swp)
<xarray.Dataset>
Dimensions:     (azimuth: 360, range: 200)
Coordinates: (12/16)
  * azimuth     (azimuth) float32 0.5 1.5 2.5 3.5 ... 356.5 357.5 358.5 359.5
    elevation   (azimuth) float32 32.0 32.0 32.0 32.0 ... 32.0 32.0 32.0 32.0
    rtime       (azimuth) datetime64[ns] 2018-12-20T07:28:41.598600960 ... 20...
  * range       (range) float32 125.0 375.0 625.0 ... 4.962e+04 4.988e+04
    time        datetime64[ns] 2018-12-20T07:28:37
    sweep_mode  <U20 'azimuth_surveillance'
    ...          ...
    y           (azimuth, range) float32 106.0 318.0 ... 4.195e+04 4.216e+04
    z           (azimuth, range) float32 262.0 395.0 ... 2.66e+04 2.673e+04
    gr          (azimuth, range) float32 106.0 318.0 ... 4.195e+04 4.216e+04
    rays        (azimuth, range) float32 0.5 0.5 0.5 0.5 ... 359.5 359.5 359.5
    bins        (azimuth, range) float32 125.0 375.0 ... 4.962e+04 4.988e+04
    height      (range) float32 262.0 395.0 527.0 ... 2.66e+04 2.673e+04
Data variables:
    DBZH        (azimuth, range) float32 nan 0.5 7.5 3.0 ... nan nan nan nan
    VRADH       (azimuth, range) float32 -25.99 -11.35 -4.951 ... nan nan nan
    WRADH       (azimuth, range) float32 7.17 1.639 5.224 3.892 ... nan nan nan
    TH          (azimuth, range) float32 15.5 1.0 7.5 3.0 ... nan nan nan nan
    ZDR         (azimuth, range) float32 nan 1.606 3.102 1.134 ... nan nan nan
    RHOHV       (azimuth, range) float32 nan 0.9803 0.7756 0.748 ... nan nan nan
    PHIDP       (azimuth, range) float32 nan 121.9 103.5 121.9 ... nan nan nan
    SNRH        (azimuth, range) float32 52.5 48.5 51.0 43.5 ... 0.5 0.0 1.5 1.0
Attributes:
    fixed_angle:  32.0
qvp = swp.mean("azimuth")
qvp
<xarray.Dataset>
Dimensions:     (range: 200)
Coordinates:
  * range       (range) float32 125.0 375.0 625.0 ... 4.962e+04 4.988e+04
    time        datetime64[ns] 2018-12-20T07:28:37
    sweep_mode  <U20 'azimuth_surveillance'
    longitude   float64 151.2
    latitude    float64 -33.7
    altitude    float64 195.0
    height      (range) float32 262.0 395.0 527.0 ... 2.66e+04 2.673e+04
Data variables:
    DBZH        (range) float32 1.143 -1.34 4.022 6.988 ... nan nan nan nan
    VRADH       (range) float32 -3.843 -2.17 -3.047 -3.86 ... nan nan nan nan
    WRADH       (range) float32 6.623 4.058 4.071 3.56 3.372 ... nan nan nan nan
    TH          (range) float32 15.55 2.456 6.001 7.233 ... nan nan nan nan
    ZDR         (range) float32 -2.409 2.278 1.928 1.512 ... nan nan nan nan
    RHOHV       (range) float32 0.1409 0.6495 0.7601 0.8402 ... nan nan nan nan
    PHIDP       (range) float32 256.0 104.2 112.2 115.2 ... nan nan nan nan
    SNRH        (range) float32 55.48 46.51 47.43 47.48 ... 0.5639 0.5159 0.6967
qvp.DBZH.plot(y="height", figsize=(5, 10))
[<matplotlib.lines.Line2D at 0x7f53b24d8a30>]
../../_images/wradlib_quasi_vertical_profiles_18_1.png

TimeSeries QVP

All wradlib xarray backends have the capability to read multiple sweeps/volumes in one go. We have to prepare the list of files a bit, though.

ts = xr.open_mfdataset(
    idr71,
    engine="odim",
    group="dataset1",
    combine="nested",
    concat_dim="time",
)
display(ts)
<xarray.Dataset>
Dimensions:     (time: 40, azimuth: 360, range: 200)
Coordinates:
  * azimuth     (azimuth) float32 0.5 1.5 2.5 3.5 ... 356.5 357.5 358.5 359.5
    elevation   (azimuth) float32 dask.array<chunksize=(360,), meta=np.ndarray>
    rtime       (time, azimuth) datetime64[ns] dask.array<chunksize=(1, 360), meta=np.ndarray>
  * range       (range) float32 125.0 375.0 625.0 ... 4.962e+04 4.988e+04
  * time        (time) datetime64[ns] 2018-12-20T05:04:32 ... 2018-12-20T08:5...
    sweep_mode  <U20 'azimuth_surveillance'
    longitude   float64 151.2
    latitude    float64 -33.7
    altitude    float64 195.0
Data variables:
    DBZH        (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    VRADH       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    WRADH       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    TH          (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    ZDR         (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    RHOHV       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    PHIDP       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    SNRH        (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
Attributes:
    fixed_angle:  32.0

Georeference and add height coordinate

ts = ts.pipe(add_height)
display(ts)
<xarray.Dataset>
Dimensions:     (time: 40, azimuth: 360, range: 200)
Coordinates: (12/16)
  * azimuth     (azimuth) float32 0.5 1.5 2.5 3.5 ... 356.5 357.5 358.5 359.5
    elevation   (azimuth) float32 dask.array<chunksize=(360,), meta=np.ndarray>
    rtime       (time, azimuth) datetime64[ns] dask.array<chunksize=(1, 360), meta=np.ndarray>
  * range       (range) float32 125.0 375.0 625.0 ... 4.962e+04 4.988e+04
  * time        (time) datetime64[ns] 2018-12-20T05:04:32 ... 2018-12-20T08:5...
    sweep_mode  <U20 'azimuth_surveillance'
    ...          ...
    y           (azimuth, range) float32 106.0 318.0 ... 4.195e+04 4.216e+04
    z           (azimuth, range) float32 262.0 395.0 ... 2.66e+04 2.673e+04
    gr          (azimuth, range) float32 106.0 318.0 ... 4.195e+04 4.216e+04
    rays        (azimuth, range) float32 0.5 0.5 0.5 0.5 ... 359.5 359.5 359.5
    bins        (azimuth, range) float32 125.0 375.0 ... 4.962e+04 4.988e+04
    height      (range) float32 262.0 395.0 527.0 ... 2.66e+04 2.673e+04
Data variables:
    DBZH        (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    VRADH       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    WRADH       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    TH          (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    ZDR         (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    RHOHV       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    PHIDP       (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
    SNRH        (time, azimuth, range) float32 dask.array<chunksize=(1, 360, 200), meta=np.ndarray>
Attributes:
    fixed_angle:  32.0

Calculate Statistics

stats = ["median", "mean", "min", "max"]
stat = [
    getattr(ts.where(ts.RHOHV > 0.8), st)("azimuth", skipna=True, keep_attrs=True)
    for st in stats
]
ts_stats = xr.concat(stat, dim="stats")
ts_stats = ts_stats.assign_coords({"stats": stats})
display(ts_stats)
<xarray.Dataset>
Dimensions:     (stats: 4, time: 40, range: 200)
Coordinates:
  * range       (range) float32 125.0 375.0 625.0 ... 4.962e+04 4.988e+04
  * time        (time) datetime64[ns] 2018-12-20T05:04:32 ... 2018-12-20T08:5...
    sweep_mode  <U20 'azimuth_surveillance'
    longitude   float64 151.2
    latitude    float64 -33.7
    altitude    float64 195.0
    height      (range) float32 262.0 395.0 527.0 ... 2.66e+04 2.673e+04
  * stats       (stats) <U6 'median' 'mean' 'min' 'max'
Data variables:
    DBZH        (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    VRADH       (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    WRADH       (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    TH          (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    ZDR         (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    RHOHV       (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    PHIDP       (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
    SNRH        (stats, time, range) float32 dask.array<chunksize=(1, 1, 200), meta=np.ndarray>
Attributes:
    fixed_angle:  32.0

Plot QVP’s

levels = np.arange(-30, 80, 5)
facet = ts_stats.TH.plot(
    x="time",
    y="height",
    col="stats",
    col_wrap=2,
    cmap="turbo",
    figsize=(12, 10),
    levels=levels,
)
/srv/conda/envs/notebook/lib/python3.9/site-packages/dask/array/reductions.py:640: RuntimeWarning: All-NaN slice encountered
  return np.nanmax(x_chunk, axis=axis, keepdims=keepdims)
/srv/conda/envs/notebook/lib/python3.9/site-packages/dask/array/reductions.py:611: RuntimeWarning: All-NaN slice encountered
  return np.nanmin(x_chunk, axis=axis, keepdims=keepdims)
/srv/conda/envs/notebook/lib/python3.9/site-packages/numpy/lib/nanfunctions.py:1217: RuntimeWarning: All-NaN slice encountered
  r, k = function_base._ureduce(a, func=_nanmedian, axis=axis, out=out,
../../_images/wradlib_quasi_vertical_profiles_28_1.png

Summary

Easy creation of Quasi Vertical Profiles was shown.