Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Inspect Dual Pol Data - Jastrebac

radar datatree Logo
xradar Logo
xarray Logo
wradlib Logo

Inspect Dual Pol Data - Jastrebac

Jastrebac radar is located on top of the mountain range of the same name Jastrebac west of Niŝ.

Claim Data

We use the ARCO data provided in Data Access — Serbian Rainbow Radar. Please refer to this notebook for details of access.

OSN_ENDPOINT = "https://umn1.osn.mghpcc.org"
BUCKET = "nexrad-arco"
# prefix = "jastrebac_250m"  # dual-pol, 12 × 360 × 1000, 2014 only
prefix = "jastrebac_500m"  # dual-pol, 12 × 360 × 500,  2017 + 2026

storage = icechunk.s3_storage(
    bucket=BUCKET,
    prefix=prefix,
    endpoint_url=OSN_ENDPOINT,
    region="us-east-1",
    anonymous=True,
    force_path_style=True,
)
repo = icechunk.Repository.open(storage)
dtree = xr.open_datatree(
    repo.readonly_session("main").store,
    engine="zarr",
    consolidated=False,
    chunks={},
)
display(dtree)
root = next(iter(dtree.keys())).split("/")[0]
Loading...

Radar domain

Get lowest elevation sweep

First we get the lowest sweep and do some georeferencing.

swp = (
    dtree[f"{root}/sweep_0"]
    .to_dataset()
    .assign_coords(dtree[root].coords)
    .assign_coords(sweep_mode="azimuth_surveillance")
    .wrl.georef.georeference(crs=wrl.georef.get_earth_projection())
)
swp.x.attrs = xd.model.get_longitude_attrs()
swp.y.attrs = xd.model.get_latitude_attrs()
swp.z.attrs = xd.model.get_altitude_attrs()
display(swp)
Loading...

Plot over Maptiles

Use the bokeh infrastructure to interact with the plot.

import holoviews as hv
import geopandas as gpd
from shapely.geometry import Point
import hvplot.pandas

lon, lat = swp.longitude.values, swp.latitude.values

radar = gpd.GeoDataFrame(
    geometry=[
        Point(lon, lat),
    ],
    crs="EPSG:4326",
)

lon_domain = swp.isel(range=-1).x.values
lat_domain = swp.isel(range=-1).y.values
ring = gpd.GeoDataFrame(
    geometry=[Point(xy) for xy in zip(lon_domain, lat_domain)],
    crs="EPSG:4326"
)

tiles = hv.element.tiles.OpenTopoMap()

points = radar.hvplot.points(
    x="lon",
    y="lat",
    marker="o",
    geo=True,
    s=100,
    c="red",
    tiles=tiles,
)

domain = ring.hvplot(
    geo=True,
    line_width=2,
    color="blue",
)

(points * domain).opts(
    frame_width=600,
    # height=600,
)
Loading...
Loading...
Loading...
Loading...
Loading...

Scan pattern

TTo visualize the scan pattern we just select a single volume.

svol = dtree[root].isel(vcp_time=0)
display(svol)
for c, v in svol.coords.items():
    print(c, v.values)
for c in sorted(svol.children, key=lambda x: int(x.split("_")[-1])):
    print(c, svol[c].time.isel(azimuth=0).values)
Loading...
altitude 1522.0
latitude 43.39116
prt_mode not_set
follow_mode not_set
longitude 21.44335
vcp_time 2017-08-12T15:05:06.000000000
sweep_mode azimuth_surveillance
sweep_0 2017-08-12T15:05:07.854166528
sweep_1 2017-08-12T15:05:38.604166400
sweep_2 2017-08-12T15:05:53.479166500
sweep_3 2017-08-12T15:06:08.354166528
sweep_4 2017-08-12T15:06:23.062500096
sweep_5 2017-08-12T15:06:38.604166500
sweep_6 2017-08-12T15:06:53.270833500
sweep_7 2017-08-12T15:07:07.645833472
sweep_8 2017-08-12T15:07:38.104166400
sweep_9 2017-08-12T15:07:52.520833500
sweep_10 2017-08-12T15:08:07.687500000
sweep_11 2017-08-12T15:08:22.770833500
ax = svol.wrl.vis.plot_scan_strategy()
<Figure size 1600x800 with 1 Axes>

Overview Plot

Select a time slot and plot four radar moments!

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(12, 10))
dbz_min, dbz_max = (0, 50)

swp_sel = swp.sel(vcp_time="2014-05-15T00:01:50", method="nearest")

swp_sel.DBTH.wrl.vis.plot(ax=ax1, vmin=dbz_min, vmax=dbz_max)
ax1.set_title("DBTH")
swp_sel.DBZH.wrl.vis.plot(ax=ax2, vmin=dbz_min, vmax=dbz_max)
ax2.set_title("DBZH")
swp_sel.VRADH.wrl.vis.plot(ax=ax3)
ax3.set_title("VRADH")
swp_sel.WRADH.wrl.vis.plot(ax=ax4, vmin=0, vmax=6)
ax4.set_title("WRADH")

fig.tight_layout()
<Figure size 1200x1000 with 8 Axes>
hv.extension('bokeh')
hv.output(widget_location="bottom")

swpx = swp.chunk()

dbz_opts = dict(
    cmap="HomeyerRainbow", 
    clim=(0, 60), 
    aspect=1
)

vrad_opts = dict(
    cmap="Seismic", 
    clim=(-15, 15), 
    aspect=1
)

wrad_opts = dict(
    cmap="Seismic", 
    clim=(0, 15), 
    aspect=1
)


dbth = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="DBTH", frame_width=250, rasterize=True)   
).opts(axiswise=False, xaxis=None, **dbz_opts)

dbzh = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="DBZH", frame_width=250, rasterize=True)   
).opts(axiswise=False, xaxis=None, yaxis=None, **dbz_opts)

vradh = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="VRADH", frame_width=250, rasterize=True)   
).opts(axiswise=False, **vrad_opts)

wradh = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="WRADH", frame_width=250, rasterize=True)   
).opts(axiswise=False, yaxis=None, **vrad_opts)



layout = (dbth + dbzh + vradh + wradh).cols(2)
layout
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...

Overview Polarimetric Data

Matplotlib

Select a time slot and plot four polarimetric radar moments!

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=True, figsize=(12, 10))
dbz_min, dbz_max = (0, 50)

swp_sel = swp.sel(vcp_time="2014-05-15T00:01:50", method="nearest")

swp_sel.ZDR.wrl.vis.plot(ax=ax1, vmin=-0.5, vmax=5)
ax1.set_title("ZDR")
swp_sel.RHOHV.wrl.vis.plot(ax=ax2, cmap="plasmidis")
ax2.set_title("RHOHV")
swp_sel.PHIDP.wrl.vis.plot(ax=ax3, vmin=0, vmax=60, cmap="ChaseSpectral")
ax3.set_title("PHIDP")
swp_sel.KDP.wrl.vis.plot(ax=ax4, vmin=-0.5, vmax=2)
ax4.set_title("KDP")
#
fig.tight_layout()
<Figure size 1200x1000 with 8 Axes>

Bokeh

hv.extension('bokeh')
hv.output(widget_location="bottom")

swpx = swp.chunk()

zdr_opts = dict(
    cmap="HomeyerRainbow", 
    clim=(-0.5, 5), 
    aspect=1
)

rho_opts = dict(
    cmap="plasmidis", 
    clim=(0.0, 1.0), 
    aspect=1
)

phi_opts = dict(
    cmap="Seismic", 
    clim=(0, 60), 
    aspect=1
)

kdp_opts = dict(
    cmap="Seismic", 
    clim=(-0.5, 2), 
    aspect=1
)

zdr = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="ZDR", frame_width=250, rasterize=True)   
).opts(axiswise=False, xaxis=None, **zdr_opts)

rhohv = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="RHOHV", frame_width=250, rasterize=True)   
).opts(axiswise=False, xaxis=None, yaxis=None, **rho_opts)

phidp = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="PHIDP", frame_width=250, rasterize=True)   
).opts(axiswise=False, **phi_opts)

kdp = (
    swpx.hvplot.quadmesh(groupby="vcp_time", x="x", y="y", z="KDP", frame_width=250, rasterize=True)   
).opts(axiswise=False, yaxis=None, **kdp_opts)

layout = (zdr + rhohv + phidp + kdp).cols(2)
layout
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...