Example for georeferencing a radar dataset#
import warnings
import matplotlib as mpl
import matplotlib.pyplot as plt
import wradlib as wrl
import xradar as xd
from matplotlib.patches import Rectangle
warnings.filterwarnings("ignore")
1st step: Compute centroid coordinates and vertices of all radar bins in WGS84 (longitude and latitude).
swp = (
xd.model.create_sweep_dataset(rng=1000)
.swap_dims(time="azimuth")
.isel(range=slice(0, 100))
)
swp = swp.assign_coords(sweep_mode="azimuthal_surveillance")
swp = swp.wrl.georef.georeference()
swp
<xarray.Dataset> Size: 2MB
Dimensions: (azimuth: 360, range: 100)
Coordinates: (12/15)
* azimuth (azimuth) float64 3kB 0.5 1.5 2.5 3.5 ... 357.5 358.5 359.5
time (azimuth) datetime64[ns] 3kB 2022-08-27T10:00:00 ... 2022-08-...
elevation (azimuth) float64 3kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
* range (range) float64 800B 500.0 1.5e+03 2.5e+03 ... 9.85e+04 9.95e+04
x (azimuth, range) float64 288kB 4.362 13.09 ... -859.2 -867.9
y (azimuth, range) float64 288kB 499.9 1.5e+03 ... 9.945e+04
... ...
bins (azimuth, range) float64 288kB 500.0 1.5e+03 ... 9.95e+04
longitude float64 8B 8.788
latitude float64 8B 46.17
altitude int64 8B 375
sweep_mode <U22 88B 'azimuthal_surveillance'
crs_wkt int64 8B 0
Data variables:
*empty*We can now generate the polygon vertices of the radar bins - with each vertex in lon/lat coordinates.
proj_wgs84 = wrl.georef.epsg_to_osr(4326)
polygons = swp.wrl.georef.spherical_to_polyvert(crs=proj_wgs84, keep_attrs=True)
polygons
<xarray.DataArray 'spherical_to_polyvert' (bins: 36000, vert: 5, xy: 3)> Size: 4MB
array([[[ 8.787727 , 46.172541 , 375. ],
[ 8.787727 , 46.18153568, 392.51128273],
[ 8.78795299, 46.18153431, 392.51128273],
[ 8.787727 , 46.172541 , 375. ],
[ 8.787727 , 46.172541 , 375. ]],
[[ 8.787727 , 46.18153568, 392.51128273],
[ 8.787727 , 46.19053031, 410.14031758],
[ 8.78817906, 46.19052756, 410.14031758],
[ 8.78795299, 46.18153431, 392.51128273],
[ 8.787727 , 46.18153568, 392.51128273]],
[[ 8.787727 , 46.19053031, 410.14031758],
[ 8.787727 , 46.19952488, 427.8871038 ],
[ 8.7884052 , 46.19952077, 427.8871038 ],
[ 8.78817906, 46.19052756, 410.14031758],
[ 8.787727 , 46.19053031, 410.14031758]],
...,
[[ 8.76546085, 47.04461365, 2621.72317735],
[ 8.76522761, 47.05360076, 2650.65223704],
[ 8.78772694, 47.05373714, 2650.65223704],
[ 8.78772694, 47.04474861, 2621.72317735],
[ 8.76546085, 47.04461365, 2621.72317735]],
[[ 8.76522761, 47.05360076, 2650.65223704],
[ 8.76499429, 47.06258781, 2679.69900768],
[ 8.78772694, 47.0627256 , 2679.69900768],
[ 8.78772694, 47.05373714, 2650.65223704],
[ 8.76522761, 47.05360076, 2650.65223704]],
[[ 8.76499429, 47.06258781, 2679.69900768],
[ 8.76476089, 47.07157477, 2708.86342778],
[ 8.78772694, 47.07171398, 2708.86342778],
[ 8.78772694, 47.0627256 , 2679.69900768],
[ 8.76499429, 47.06258781, 2679.69900768]]],
shape=(36000, 5, 3))
Coordinates:
longitude float64 8B 8.788
latitude float64 8B 46.17
altitude int64 8B 375
sweep_mode <U22 88B 'azimuthal_surveillance'
crs_wkt int64 8B 0
Dimensions without coordinates: bins, vert, xy
Attributes:
units: meters
standard_name: projection_range_coordinate
long_name: range_to_measurement_volume
axis: radial_range_coordinate
meters_between_gates: 1000.0
spacing_is_constant: true
meters_to_center_of_first_gate: 500.0… or we can compute the corresponding centroids of all bins - - with each centroid in lon/lat coordinates.
centroids = swp.wrl.georef.spherical_to_centroids(crs=proj_wgs84, keep_attrs=True)
centroids
<xarray.DataArray 'spherical_to_centroids' (azimuth: 360, range: 100, xyz: 3)> Size: 864kB
array([[[ 8.7877835 , 46.17703817, 383.74092231],
[ 8.78789652, 46.18603248, 401.31108119],
[ 8.78800957, 46.19502674, 418.99899181],
...,
[ 8.79891893, 47.04920895, 2636.17297817],
[ 8.79903558, 47.05819709, 2665.16095378],
[ 8.79915226, 47.06718516, 2694.26651916]],
[[ 8.78789647, 46.1770368 , 383.74092231],
[ 8.7882355 , 46.18602837, 401.31108119],
[ 8.78857463, 46.19501989, 418.99899181],
...,
[ 8.82129918, 47.04893762, 2636.17297817],
[ 8.82164908, 47.05792293, 2665.16095378],
[ 8.82199909, 47.06690816, 2694.26651916]],
[[ 8.7880094 , 46.17703406, 383.74092231],
[ 8.78857432, 46.18602015, 401.31108119],
[ 8.78913943, 46.19500619, 418.99899181],
...,
...
[ 8.73178512, 47.048395 , 2636.17297817],
[ 8.73120208, 47.05737466, 2665.16095378],
[ 8.73061885, 47.06635424, 2694.26651916]],
[[ 8.78755753, 46.1770368 , 383.74092231],
[ 8.78721851, 46.18602837, 401.31108119],
[ 8.78687937, 46.19501989, 418.99899181],
...,
[ 8.75415509, 47.04893762, 2636.17297817],
[ 8.75380519, 47.05792293, 2665.16095378],
[ 8.75345518, 47.06690816, 2694.26651916]],
[[ 8.7876705 , 46.17703817, 383.74092231],
[ 8.78755749, 46.18603248, 401.31108119],
[ 8.78744443, 46.19502674, 418.99899181],
...,
[ 8.77653518, 47.04920895, 2636.17297817],
[ 8.77641854, 47.05819709, 2665.16095378],
[ 8.77630185, 47.06718516, 2694.26651916]]],
shape=(360, 100, 3))
Coordinates:
* azimuth (azimuth) float64 3kB 0.5 1.5 2.5 3.5 ... 357.5 358.5 359.5
time (azimuth) datetime64[ns] 3kB 2022-08-27T10:00:00 ... 2022-08-...
elevation (azimuth) float64 3kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
* range (range) float64 800B 500.0 1.5e+03 2.5e+03 ... 9.85e+04 9.95e+04
longitude float64 8B 8.788
latitude float64 8B 46.17
altitude int64 8B 375
sweep_mode <U22 88B 'azimuthal_surveillance'
crs_wkt int64 8B 0
Dimensions without coordinates: xyz
Attributes:
units: meters
standard_name: projection_range_coordinate
long_name: range_to_measurement_volume
axis: radial_range_coordinate
meters_between_gates: 1000.0
spacing_is_constant: true
meters_to_center_of_first_gate: 500.0In order to understand how vertices and centroids correspond, we can plot them together.
fig = plt.figure(figsize=(16, 16))
site = (polygons.longitude.values, polygons.latitude.values)
aspect = (centroids[..., 0].max() - centroids[..., 0].min()) / (
centroids[..., 1].max() - centroids[..., 1].min()
)
ax = fig.add_subplot(121, aspect=aspect)
polycoll = mpl.collections.PolyCollection(
polygons.isel(xy=slice(0, 2)), closed=True, facecolors="None", linewidth=0.1
)
ax.add_collection(polycoll, autolim=True)
# ax.plot(centroids[..., 0], centroids[..., 1], 'r+')
plt.title("Zoom in\n(only possible for interactive plots).")
ax.add_patch(
Rectangle(
(site[0] + 0.25, site[1] + 0.25),
0.2,
0.2 / aspect,
edgecolor="red",
facecolor="None",
zorder=3,
)
)
plt.xlim(centroids[..., 0].min(), centroids[..., 0].max())
plt.ylim(centroids[..., 1].min(), centroids[..., 1].max())
ax = fig.add_subplot(122, aspect=aspect)
polycoll = mpl.collections.PolyCollection(
polygons.isel(xy=slice(0, 2)), closed=True, facecolors="None"
)
ax.add_collection(polycoll, autolim=True)
ax.plot(centroids[..., 0], centroids[..., 1], "r+")
plt.title("Zoom into red box of left plot")
plt.xlim(site[0] + 0.25, site[0] + 0.25 + 0.2)
plt.ylim(site[1] + 0.25, site[1] + 0.25 + 0.2 / aspect)
(46.422541, 46.56147892646726)
2nd step: Reproject the centroid coordinates to Gauss-Krueger Zone 3 (i.e. EPSG-Code 31467).
centroids_xyz = centroids.assign_coords(xyz=["x", "y", "z"]).to_dataset("xyz")
centroids_xyz
<xarray.Dataset> Size: 874kB
Dimensions: (azimuth: 360, range: 100)
Coordinates:
* azimuth (azimuth) float64 3kB 0.5 1.5 2.5 3.5 ... 357.5 358.5 359.5
time (azimuth) datetime64[ns] 3kB 2022-08-27T10:00:00 ... 2022-08-...
elevation (azimuth) float64 3kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
* range (range) float64 800B 500.0 1.5e+03 2.5e+03 ... 9.85e+04 9.95e+04
longitude float64 8B 8.788
latitude float64 8B 46.17
altitude int64 8B 375
sweep_mode <U22 88B 'azimuthal_surveillance'
crs_wkt int64 8B 0
Data variables:
x (azimuth, range) float64 288kB 8.788 8.788 8.788 ... 8.776 8.776
y (azimuth, range) float64 288kB 46.18 46.19 46.2 ... 47.06 47.07
z (azimuth, range) float64 288kB 383.7 401.3 ... 2.694e+03
Attributes:
units: meters
standard_name: projection_range_coordinate
long_name: range_to_measurement_volume
axis: radial_range_coordinate
meters_between_gates: 1000.0
spacing_is_constant: true
meters_to_center_of_first_gate: 500.0proj_gk3 = wrl.georef.epsg_to_osr(31467)
centroids_xyz = centroids_xyz.wrl.georef.reproject(trg_crs=proj_gk3)
centroids_xyz
<xarray.Dataset> Size: 874kB
Dimensions: (azimuth: 360, range: 100)
Coordinates:
* azimuth (azimuth) float64 3kB 0.5 1.5 2.5 3.5 ... 357.5 358.5 359.5
time (azimuth) datetime64[ns] 3kB 2022-08-27T10:00:00 ... 2022-08-...
elevation (azimuth) float64 3kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
* range (range) float64 800B 500.0 1.5e+03 2.5e+03 ... 9.85e+04 9.95e+04
x (azimuth, range) float64 288kB 3.484e+06 3.484e+06 ... 3.484e+06
y (azimuth, range) float64 288kB 5.115e+06 5.115e+06 ... 5.115e+06
z (azimuth, range) float64 288kB 383.7 401.3 ... 2.694e+03
longitude float64 8B 8.788
latitude float64 8B 46.17
altitude int64 8B 375
sweep_mode <U22 88B 'azimuthal_surveillance'
crs_wkt int64 8B 0
Data variables:
*empty*
Attributes:
units: meters
standard_name: projection_range_coordinate
long_name: range_to_measurement_volume
axis: radial_range_coordinate
meters_between_gates: 1000.0
spacing_is_constant: true
meters_to_center_of_first_gate: 500.0