ToGrid#
In this notebook we show the production of a reflectivity composite from 3 neighboring radars to a common cartesian grid, using the sampling volume size as a quality criterion.
import tempfile
import warnings
import cmweather
import numpy as np
import pyproj
import xarray as xr
import matplotlib.pyplot as plt
import wradlib as wrl
import wradlib_data
warnings.filterwarnings("ignore")
/home/docs/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
from .autonotebook import tqdm as notebook_tqdm
Get radar data#
First, we import measurements from three belgian radars. This is done using xarray.open_dataset using xradar.io.backends.odim.OdimBackendEntrypoint.
filenames = ["bejab.pvol.hdf", "bewid.pvol.hdf", "behel.pvol.hdf"]
paths = {f.split(".")[0][2:]: wradlib_data.DATASETS.fetch(f"hdf5/{f}") for f in filenames}
ctree = xr.DataTree()
for radar, filename in paths.items():
ctree[radar] = xr.open_dataset(filename, engine="odim", group="sweep_0").chunk().wrl.georef.georeference().set_coords("sweep_mode")
display(ctree)
<xarray.DataTree>
Group: /
├── Group: /jab
│ Dimensions: (azimuth: 360, range: 598)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 2kB 250.0 750.0 ... 2.982e+05 2.988e+05
│ x (azimuth, range) float64 2MB 2.182 6.545 ... -2.605e+03
│ y (azimuth, range) float64 2MB 250.0 750.0 ... 2.986e+05
│ ... ...
│ bins (azimuth, range) float32 861kB 250.0 750.0 ... 2.988e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 3.064
│ latitude float64 8B 51.19
│ altitude float64 8B 50.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 598), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ Attributes:
│ Conventions: ODIM_H5/V2_2
├── Group: /wid
│ Dimensions: (azimuth: 360, range: 1000)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 4kB 125.0 375.0 ... 2.496e+05 2.499e+05
│ x (azimuth, range) float64 3MB 1.091 3.272 ... -2.179e+03
│ y (azimuth, range) float64 3MB 125.0 375.0 ... 2.497e+05
│ ... ...
│ bins (azimuth, range) float32 1MB 125.0 375.0 ... 2.499e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 5.506
│ latitude float64 8B 49.91
│ altitude float64 8B 590.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 3MB dask.array<chunksize=(360, 1000), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ Attributes:
│ Conventions: ODIM_H5/V2_2
└── Group: /hel
Dimensions: (azimuth: 360, range: 800)
Coordinates: (12/15)
* azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
* range (range) float32 3kB 125.0 375.0 ... 1.996e+05 1.999e+05
x (azimuth, range) float64 2MB 1.091 3.272 ... -1.744e+03
y (azimuth, range) float64 2MB 125.0 375.0 ... 1.998e+05
... ...
bins (azimuth, range) float32 1MB 125.0 375.0 ... 1.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
longitude float64 8B 5.406
latitude float64 8B 51.07
altitude float64 8B 140.0
crs_wkt int64 8B 0
Data variables:
DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 800), meta=np.ndarray>
sweep_number int64 8B ...
prt_mode <U7 28B ...
follow_mode <U7 28B ...
sweep_fixed_angle float64 8B ...
nyquist_velocity object 8B ...
Attributes:
Conventions: ODIM_H5/V2_2Plot Overview#
fig, axs = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
ax = axs.flat[0]
ctree["jab"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Jabbeke")
ax = axs.flat[1]
ctree["wid"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Wideumont")
ax = axs.flat[2]
ctree["hel"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Helchteren")
fig.tight_layout()
Georeference UTM#
proj_utm = pyproj.CRS.from_epsg(32632)
kwargs = dict(crs=proj_utm)
for radar in ctree.children:
ctree[radar].ds = ctree[radar].ds.wrl.georef.georeference(crs=proj_utm)
display(ctree)
<xarray.DataTree>
Group: /
├── Group: /jab
│ Dimensions: (azimuth: 360, range: 598)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 2kB 250.0 750.0 ... 2.982e+05 2.988e+05
│ x (azimuth, range) float64 2MB 8.539e+04 ... 1.074e+05
│ y (azimuth, range) float64 2MB 5.688e+06 ... 5.986e+06
│ ... ...
│ bins (azimuth, range) float32 861kB 250.0 750.0 ... 2.988e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 3.064
│ latitude float64 8B 51.19
│ altitude float64 8B 50.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 598), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ Attributes:
│ Conventions: ODIM_H5/V2_2
├── Group: /wid
│ Dimensions: (azimuth: 360, range: 1000)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 4kB 125.0 375.0 ... 2.496e+05 2.499e+05
│ x (azimuth, range) float64 3MB 2.492e+05 ... 2.588e+05
│ y (azimuth, range) float64 3MB 5.535e+06 ... 5.785e+06
│ ... ...
│ bins (azimuth, range) float32 1MB 125.0 375.0 ... 2.499e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 5.506
│ latitude float64 8B 49.91
│ altitude float64 8B 590.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 3MB dask.array<chunksize=(360, 1000), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ Attributes:
│ Conventions: ODIM_H5/V2_2
└── Group: /hel
Dimensions: (azimuth: 360, range: 800)
Coordinates: (12/15)
* azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
* range (range) float32 3kB 125.0 375.0 ... 1.996e+05 1.999e+05
x (azimuth, range) float64 2MB 2.483e+05 ... 2.564e+05
y (azimuth, range) float64 2MB 5.664e+06 ... 5.863e+06
... ...
bins (azimuth, range) float32 1MB 125.0 375.0 ... 1.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
longitude float64 8B 5.406
latitude float64 8B 51.07
altitude float64 8B 140.0
crs_wkt int64 8B 0
Data variables:
DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 800), meta=np.ndarray>
sweep_number int64 8B ...
prt_mode <U7 28B ...
follow_mode <U7 28B ...
sweep_fixed_angle float64 8B ...
nyquist_velocity object 8B ...
Attributes:
Conventions: ODIM_H5/V2_2fig, axs = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
ax = axs.flat[0]
ctree["jab"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Jabbeke")
ax = axs.flat[1]
ctree["wid"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Wideumont")
ax = axs.flat[2]
ctree["hel"].ds.DBZH.wrl.vis.plot(ax=ax, vmin=0, vmax=60)
ax.set_aspect("equal")
ax.set_title("Radar Helchteren")
fig.tight_layout()
Error in callback <function _draw_all_if_interactive at 0x7af7b5ccaca0> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/pyplot.py:300, in _draw_all_if_interactive()
298 def _draw_all_if_interactive() -> None:
299 if matplotlib.is_interactive():
--> 300 draw_all()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/_pylab_helpers.py:133, in Gcf.draw_all(cls, force)
131 for manager in cls.get_all_fig_managers():
132 if force or manager.canvas.figure.stale:
--> 133 manager.canvas.draw_idle()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:1989, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
1987 if not self._is_idle_drawing:
1988 with self._idle_draw_cntx():
-> 1989 self.draw(*args, **kwargs)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backends/backend_agg.py:438, in FigureCanvasAgg.draw(self)
435 # Acquire a lock on the shared font cache.
436 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
437 else nullcontext()):
--> 438 self.figure.draw(self.renderer)
439 # A GUI class may be need to update a window using this draw, so
440 # don't forget to call the superclass.
441 super().draw()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3271, in Figure.draw(self, renderer)
3267 return
3269 with self._render_lock:
-> 3271 artists = self._get_draw_artists(renderer)
3272 try:
3273 renderer.open_group('figure', gid=self.get_gid())
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:166, in FigureBase._get_draw_artists(self, renderer)
164 for ax in self._localaxes:
165 locator = ax.get_axes_locator()
--> 166 ax.apply_aspect(locator(ax, renderer) if locator else None)
168 for child in ax.get_children():
169 if hasattr(child, 'apply_aspect'):
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:2127, in _AxesBase.apply_aspect(self, position)
2124 if not self.get_autoscalex_on():
2125 _log.warning("Ignoring fixed x limits to fulfill fixed data aspect "
2126 "with adjustable data limits.")
-> 2127 self.set_xbound(x_trf.inverted().transform([x0, x1]))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3849, in _AxesBase.set_xbound(self, lower, upper)
3846 if upper is None:
3847 upper = old_upper
-> 3849 self.set_xlim(sorted((lower, upper),
3850 reverse=bool(self.xaxis_inverted())),
3851 auto=None)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3970, in _AxesBase.set_xlim(self, left, right, emit, auto, xmin, xmax)
3968 raise TypeError("Cannot pass both 'right' and 'xmax'")
3969 right = xmax
-> 3970 return self.xaxis._set_lim(left, right, emit=emit, auto=auto)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1263, in Axis._set_lim(self, v0, v1, emit, auto)
1260 name = self._get_axis_name()
1262 self.axes._process_unit_info([(name, (v0, v1))], convert=False)
-> 1263 v0 = self.axes._validate_converted_limits(v0, self.convert_units)
1264 v1 = self.axes._validate_converted_limits(v1, self.convert_units)
1266 if v0 is None or v1 is None:
1267 # Axes init calls set_xlim(0, 1) before get_xlim() can be called,
1268 # so only grab the limits if we really need them.
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3891, in _AxesBase._validate_converted_limits(self, limit, convert)
3888 converted_limit = converted_limit.squeeze()
3889 if (isinstance(converted_limit, Real)
3890 and not np.isfinite(converted_limit)):
-> 3891 raise ValueError("Axis limits cannot be NaN or Inf")
3892 return converted_limit
ValueError: Axis limits cannot be NaN or Inf
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:2249, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2246 # we do this instead of `self.figure.draw_without_rendering`
2247 # so that we can inject the orientation
2248 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2249 self.figure.draw(renderer)
2250 else:
2251 renderer = None
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3271, in Figure.draw(self, renderer)
3267 return
3269 with self._render_lock:
-> 3271 artists = self._get_draw_artists(renderer)
3272 try:
3273 renderer.open_group('figure', gid=self.get_gid())
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:166, in FigureBase._get_draw_artists(self, renderer)
164 for ax in self._localaxes:
165 locator = ax.get_axes_locator()
--> 166 ax.apply_aspect(locator(ax, renderer) if locator else None)
168 for child in ax.get_children():
169 if hasattr(child, 'apply_aspect'):
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:2127, in _AxesBase.apply_aspect(self, position)
2124 if not self.get_autoscalex_on():
2125 _log.warning("Ignoring fixed x limits to fulfill fixed data aspect "
2126 "with adjustable data limits.")
-> 2127 self.set_xbound(x_trf.inverted().transform([x0, x1]))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3849, in _AxesBase.set_xbound(self, lower, upper)
3846 if upper is None:
3847 upper = old_upper
-> 3849 self.set_xlim(sorted((lower, upper),
3850 reverse=bool(self.xaxis_inverted())),
3851 auto=None)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3970, in _AxesBase.set_xlim(self, left, right, emit, auto, xmin, xmax)
3968 raise TypeError("Cannot pass both 'right' and 'xmax'")
3969 right = xmax
-> 3970 return self.xaxis._set_lim(left, right, emit=emit, auto=auto)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1263, in Axis._set_lim(self, v0, v1, emit, auto)
1260 name = self._get_axis_name()
1262 self.axes._process_unit_info([(name, (v0, v1))], convert=False)
-> 1263 v0 = self.axes._validate_converted_limits(v0, self.convert_units)
1264 v1 = self.axes._validate_converted_limits(v1, self.convert_units)
1266 if v0 is None or v1 is None:
1267 # Axes init calls set_xlim(0, 1) before get_xlim() can be called,
1268 # so only grab the limits if we really need them.
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3891, in _AxesBase._validate_converted_limits(self, limit, convert)
3888 converted_limit = converted_limit.squeeze()
3889 if (isinstance(converted_limit, Real)
3890 and not np.isfinite(converted_limit)):
-> 3891 raise ValueError("Axis limits cannot be NaN or Inf")
3892 return converted_limit
ValueError: Axis limits cannot be NaN or Inf
<Figure size 1800x500 with 6 Axes>
Calculate Quality#
for radar in ctree.children:
rng = ctree[radar].ds.range
azimuth = ctree[radar].ds.azimuth
rscale = rng.diff("range").median().values
qual = rng.wrl.qual.pulse_volume(rscale, 1.0).expand_dims(azimuth=ctree[radar].ds.azimuth)
ctree[radar].ds = ctree[radar].ds.assign(QUAL=qual)
display(ctree)
<xarray.DataTree>
Group: /
├── Group: /jab
│ Dimensions: (azimuth: 360, range: 598)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 2kB 250.0 750.0 ... 2.982e+05 2.988e+05
│ x (azimuth, range) float64 2MB 8.539e+04 ... 1.074e+05
│ y (azimuth, range) float64 2MB 5.688e+06 ... 5.986e+06
│ ... ...
│ bins (azimuth, range) float32 861kB 250.0 750.0 ... 2.988e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 3.064
│ latitude float64 8B 51.19
│ altitude float64 8B 50.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 598), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ QUAL (azimuth, range) float64 2MB 7.477e+03 ... 1.068e+10
│ Attributes:
│ Conventions: ODIM_H5/V2_2
├── Group: /wid
│ Dimensions: (azimuth: 360, range: 1000)
│ Coordinates: (12/15)
│ * azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
│ elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
│ * range (range) float32 4kB 125.0 375.0 ... 2.496e+05 2.499e+05
│ x (azimuth, range) float64 3MB 2.492e+05 ... 2.588e+05
│ y (azimuth, range) float64 3MB 5.535e+06 ... 5.785e+06
│ ... ...
│ bins (azimuth, range) float32 1MB 125.0 375.0 ... 2.499e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 5.506
│ latitude float64 8B 49.91
│ altitude float64 8B 590.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (azimuth, range) float64 3MB dask.array<chunksize=(360, 1000), meta=np.ndarray>
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
│ QUAL (azimuth, range) float64 3MB 934.6 ... 3.735e+09
│ Attributes:
│ Conventions: ODIM_H5/V2_2
└── Group: /hel
Dimensions: (azimuth: 360, range: 800)
Coordinates: (12/15)
* azimuth (azimuth) float32 1kB 0.5 1.5 2.5 ... 357.5 358.5 359.5
elevation (azimuth) float64 3kB dask.array<chunksize=(360,), meta=np.ndarray>
time (azimuth) datetime64[ns] 3kB dask.array<chunksize=(360,), meta=np.ndarray>
* range (range) float32 3kB 125.0 375.0 ... 1.996e+05 1.999e+05
x (azimuth, range) float64 2MB 2.483e+05 ... 2.564e+05
y (azimuth, range) float64 2MB 5.664e+06 ... 5.863e+06
... ...
bins (azimuth, range) float32 1MB 125.0 375.0 ... 1.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
longitude float64 8B 5.406
latitude float64 8B 51.07
altitude float64 8B 140.0
crs_wkt int64 8B 0
Data variables:
DBZH (azimuth, range) float64 2MB dask.array<chunksize=(360, 800), meta=np.ndarray>
sweep_number int64 8B ...
prt_mode <U7 28B ...
follow_mode <U7 28B ...
sweep_fixed_angle float64 8B ...
nyquist_velocity object 8B ...
QUAL (azimuth, range) float64 2MB 934.6 8.411e+03 ... 2.39e+09
Attributes:
Conventions: ODIM_H5/V2_2Gridding#
First, we create a Datset with cartesian coordinates, which can hold our three radars.
We are using wradlib.comp.CompMethods.togrid to interpolate our sweep data to the cartesian domain.
As an interpolator we use wradlib.ipol.Nearest.
xmin, xmax, ymin, ymax = ctree.wrl.util.bbox()
x = np.linspace(xmin, xmax + 1000.0, 1000)
y = np.linspace(ymin, ymax + 1000.0, 1000)
cart = xr.Dataset(coords={"x": (["x"], x), "y": (["y"], y)})
display(cart)
<xarray.Dataset> Size: 16kB
Dimensions: (x: 1000, y: 1000)
Coordinates:
* x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.991e+05 4.999e+05
* y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.987e+06 5.988e+06
Data variables:
*empty*gtree = xr.DataTree()
for radar in ctree.children:
gridded = ctree[radar].ds.wrl.comp.togrid(cart)
gtree[radar] = gridded
display(gtree)
<xarray.DataTree>
Group: /
├── Group: /jab
│ Dimensions: (y: 1000, x: 1000)
│ Coordinates:
│ * y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.988e+06
│ * x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.999e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 3.064
│ latitude float64 8B 51.19
│ altitude float64 8B 50.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (y, x) float64 8MB dask.array<chunksize=(1000, 1000), meta=np.ndarray>
│ QUAL (y, x) float64 8MB nan nan nan nan ... nan nan nan nan
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
├── Group: /wid
│ Dimensions: (y: 1000, x: 1000)
│ Coordinates:
│ * y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.988e+06
│ * x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.999e+05
│ sweep_mode <U20 80B 'azimuth_surveillance'
│ longitude float64 8B 5.506
│ latitude float64 8B 49.91
│ altitude float64 8B 590.0
│ crs_wkt int64 8B 0
│ Data variables:
│ DBZH (y, x) float64 8MB dask.array<chunksize=(1000, 1000), meta=np.ndarray>
│ QUAL (y, x) float64 8MB nan nan nan nan ... nan nan nan nan
│ sweep_number int64 8B ...
│ prt_mode <U7 28B ...
│ follow_mode <U7 28B ...
│ sweep_fixed_angle float64 8B ...
│ nyquist_velocity object 8B ...
└── Group: /hel
Dimensions: (y: 1000, x: 1000)
Coordinates:
* y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.988e+06
* x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
longitude float64 8B 5.406
latitude float64 8B 51.07
altitude float64 8B 140.0
crs_wkt int64 8B 0
Data variables:
DBZH (y, x) float64 8MB dask.array<chunksize=(1000, 1000), meta=np.ndarray>
QUAL (y, x) float64 8MB nan nan nan nan ... nan nan nan nan
sweep_number int64 8B ...
prt_mode <U7 28B ...
follow_mode <U7 28B ...
sweep_fixed_angle float64 8B ...
nyquist_velocity object 8B ...fig, axs = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
ax = axs.flat[0]
gtree["jab"].ds.DBZH.plot(ax=ax, vmin=0, vmax=60, cmap="HomeyerRainbow")
ax.set_aspect("equal")
ax.set_title("Radar Jabbeke")
ax = axs.flat[1]
gtree["wid"].ds.DBZH.plot(ax=ax, vmin=0, vmax=60, cmap="HomeyerRainbow")
ax.set_aspect("equal")
ax.set_title("Radar Wideumont")
ax = axs.flat[2]
gtree["hel"].ds.DBZH.plot(ax=ax, vmin=0, vmax=60, cmap="HomeyerRainbow")
ax.set_aspect("equal")
ax.set_title("Radar Helchteren")
fig.tight_layout()
Error in callback <function _draw_all_if_interactive at 0x7af7b5ccaca0> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/pyplot.py:300, in _draw_all_if_interactive()
298 def _draw_all_if_interactive() -> None:
299 if matplotlib.is_interactive():
--> 300 draw_all()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/_pylab_helpers.py:133, in Gcf.draw_all(cls, force)
131 for manager in cls.get_all_fig_managers():
132 if force or manager.canvas.figure.stale:
--> 133 manager.canvas.draw_idle()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:1989, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
1987 if not self._is_idle_drawing:
1988 with self._idle_draw_cntx():
-> 1989 self.draw(*args, **kwargs)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backends/backend_agg.py:438, in FigureCanvasAgg.draw(self)
435 # Acquire a lock on the shared font cache.
436 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
437 else nullcontext()):
--> 438 self.figure.draw(self.renderer)
439 # A GUI class may be need to update a window using this draw, so
440 # don't forget to call the superclass.
441 super().draw()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3314, in _AxesBase.draw(self, renderer)
3311 for spine in self.spines.values():
3312 artists.remove(spine)
-> 3314 self._update_title_position(renderer)
3316 if not self.axison:
3317 for _axis in self._axis_map.values():
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3258, in _AxesBase._update_title_position(self, renderer)
3256 if title.get_text():
3257 for ax in axs:
-> 3258 ax.yaxis.get_tightbbox(renderer) # update offsetText
3259 if ax.yaxis.offsetText.get_text():
3260 bb = ax.yaxis.offsetText.get_tightbbox(renderer)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1425, in Axis.get_tightbbox(self, renderer, for_layout_only)
1423 if renderer is None:
1424 renderer = self.get_figure(root=True)._get_renderer()
-> 1425 ticks_to_draw = self._update_ticks()
1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1344, in Axis._update_ticks(self)
1340 # Check if major ticks should be computed.
1341 # Skip if using NullLocator or if all visible components are off.
1342 if (self._tick_group_visible(self._major_tick_kw)
1343 and not isinstance(self.get_major_locator(), NullLocator)):
-> 1344 major_locs = self.get_majorticklocs()
1345 major_labels = self.major.formatter.format_ticks(major_locs)
1346 major_ticks = self.get_major_ticks(len(major_locs))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1673, in Axis.get_majorticklocs(self)
1671 def get_majorticklocs(self):
1672 """Return this Axis' major tick locations in data coordinates."""
-> 1673 return self.major.locator()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2299, in MaxNLocator.__call__(self)
2297 def __call__(self):
2298 vmin, vmax = self.axis.get_view_interval()
-> 2299 return self.tick_values(vmin, vmax)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2307, in MaxNLocator.tick_values(self, vmin, vmax)
2304 vmin = -vmax
2305 vmin, vmax = mtransforms._nonsingular(
2306 vmin, vmax, expander=1e-13, tiny=1e-14)
-> 2307 locs = self._raw_ticks(vmin, vmax)
2309 prune = self._prune
2310 if prune == 'lower':
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2237, in MaxNLocator._raw_ticks(self, vmin, vmax)
2235 if self._nbins == 'auto':
2236 if self.axis is not None:
-> 2237 nbins = np.clip(self.axis.get_tick_space(),
2238 max(1, self._min_n_ticks - 1), 9)
2239 else:
2240 nbins = 9
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:2984, in YAxis.get_tick_space(self)
2982 size = self._get_tick_label_size('y') * 2
2983 if size > 0:
-> 2984 return int(np.floor(length / size))
2985 else:
2986 return 2**31 - 1
ValueError: cannot convert float NaN to integer
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:2249, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2246 # we do this instead of `self.figure.draw_without_rendering`
2247 # so that we can inject the orientation
2248 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2249 self.figure.draw(renderer)
2250 else:
2251 renderer = None
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3314, in _AxesBase.draw(self, renderer)
3311 for spine in self.spines.values():
3312 artists.remove(spine)
-> 3314 self._update_title_position(renderer)
3316 if not self.axison:
3317 for _axis in self._axis_map.values():
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3258, in _AxesBase._update_title_position(self, renderer)
3256 if title.get_text():
3257 for ax in axs:
-> 3258 ax.yaxis.get_tightbbox(renderer) # update offsetText
3259 if ax.yaxis.offsetText.get_text():
3260 bb = ax.yaxis.offsetText.get_tightbbox(renderer)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1425, in Axis.get_tightbbox(self, renderer, for_layout_only)
1423 if renderer is None:
1424 renderer = self.get_figure(root=True)._get_renderer()
-> 1425 ticks_to_draw = self._update_ticks()
1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1344, in Axis._update_ticks(self)
1340 # Check if major ticks should be computed.
1341 # Skip if using NullLocator or if all visible components are off.
1342 if (self._tick_group_visible(self._major_tick_kw)
1343 and not isinstance(self.get_major_locator(), NullLocator)):
-> 1344 major_locs = self.get_majorticklocs()
1345 major_labels = self.major.formatter.format_ticks(major_locs)
1346 major_ticks = self.get_major_ticks(len(major_locs))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1673, in Axis.get_majorticklocs(self)
1671 def get_majorticklocs(self):
1672 """Return this Axis' major tick locations in data coordinates."""
-> 1673 return self.major.locator()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2299, in MaxNLocator.__call__(self)
2297 def __call__(self):
2298 vmin, vmax = self.axis.get_view_interval()
-> 2299 return self.tick_values(vmin, vmax)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2307, in MaxNLocator.tick_values(self, vmin, vmax)
2304 vmin = -vmax
2305 vmin, vmax = mtransforms._nonsingular(
2306 vmin, vmax, expander=1e-13, tiny=1e-14)
-> 2307 locs = self._raw_ticks(vmin, vmax)
2309 prune = self._prune
2310 if prune == 'lower':
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2237, in MaxNLocator._raw_ticks(self, vmin, vmax)
2235 if self._nbins == 'auto':
2236 if self.axis is not None:
-> 2237 nbins = np.clip(self.axis.get_tick_space(),
2238 max(1, self._min_n_ticks - 1), 9)
2239 else:
2240 nbins = 9
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:2984, in YAxis.get_tick_space(self)
2982 size = self._get_tick_label_size('y') * 2
2983 if size > 0:
-> 2984 return int(np.floor(length / size))
2985 else:
2986 return 2**31 - 1
ValueError: cannot convert float NaN to integer
<Figure size 1800x500 with 6 Axes>
fig, axs = plt.subplots(1, 3, figsize=(18, 5), sharey=True)
ax = axs.flat[0]
gtree["jab"].ds.QUAL.plot(ax=ax)
ax.set_aspect("equal")
ax.set_title("Radar Jabbeke")
ax = axs.flat[1]
gtree["wid"].ds.QUAL.plot(ax=ax)
ax.set_aspect("equal")
ax.set_title("Radar Wideumont")
ax = axs.flat[2]
gtree["hel"].ds.QUAL.plot(ax=ax)
ax.set_aspect("equal")
ax.set_title("Radar Helchteren")
fig.tight_layout()
Error in callback <function _draw_all_if_interactive at 0x7af7b5ccaca0> (for post_execute), with arguments args (),kwargs {}:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/pyplot.py:300, in _draw_all_if_interactive()
298 def _draw_all_if_interactive() -> None:
299 if matplotlib.is_interactive():
--> 300 draw_all()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/_pylab_helpers.py:133, in Gcf.draw_all(cls, force)
131 for manager in cls.get_all_fig_managers():
132 if force or manager.canvas.figure.stale:
--> 133 manager.canvas.draw_idle()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:1989, in FigureCanvasBase.draw_idle(self, *args, **kwargs)
1987 if not self._is_idle_drawing:
1988 with self._idle_draw_cntx():
-> 1989 self.draw(*args, **kwargs)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backends/backend_agg.py:438, in FigureCanvasAgg.draw(self)
435 # Acquire a lock on the shared font cache.
436 with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
437 else nullcontext()):
--> 438 self.figure.draw(self.renderer)
439 # A GUI class may be need to update a window using this draw, so
440 # don't forget to call the superclass.
441 super().draw()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3314, in _AxesBase.draw(self, renderer)
3311 for spine in self.spines.values():
3312 artists.remove(spine)
-> 3314 self._update_title_position(renderer)
3316 if not self.axison:
3317 for _axis in self._axis_map.values():
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3258, in _AxesBase._update_title_position(self, renderer)
3256 if title.get_text():
3257 for ax in axs:
-> 3258 ax.yaxis.get_tightbbox(renderer) # update offsetText
3259 if ax.yaxis.offsetText.get_text():
3260 bb = ax.yaxis.offsetText.get_tightbbox(renderer)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1425, in Axis.get_tightbbox(self, renderer, for_layout_only)
1423 if renderer is None:
1424 renderer = self.get_figure(root=True)._get_renderer()
-> 1425 ticks_to_draw = self._update_ticks()
1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1344, in Axis._update_ticks(self)
1340 # Check if major ticks should be computed.
1341 # Skip if using NullLocator or if all visible components are off.
1342 if (self._tick_group_visible(self._major_tick_kw)
1343 and not isinstance(self.get_major_locator(), NullLocator)):
-> 1344 major_locs = self.get_majorticklocs()
1345 major_labels = self.major.formatter.format_ticks(major_locs)
1346 major_ticks = self.get_major_ticks(len(major_locs))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1673, in Axis.get_majorticklocs(self)
1671 def get_majorticklocs(self):
1672 """Return this Axis' major tick locations in data coordinates."""
-> 1673 return self.major.locator()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2299, in MaxNLocator.__call__(self)
2297 def __call__(self):
2298 vmin, vmax = self.axis.get_view_interval()
-> 2299 return self.tick_values(vmin, vmax)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2307, in MaxNLocator.tick_values(self, vmin, vmax)
2304 vmin = -vmax
2305 vmin, vmax = mtransforms._nonsingular(
2306 vmin, vmax, expander=1e-13, tiny=1e-14)
-> 2307 locs = self._raw_ticks(vmin, vmax)
2309 prune = self._prune
2310 if prune == 'lower':
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2237, in MaxNLocator._raw_ticks(self, vmin, vmax)
2235 if self._nbins == 'auto':
2236 if self.axis is not None:
-> 2237 nbins = np.clip(self.axis.get_tick_space(),
2238 max(1, self._min_n_ticks - 1), 9)
2239 else:
2240 nbins = 9
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:2984, in YAxis.get_tick_space(self)
2982 size = self._get_tick_label_size('y') * 2
2983 if size > 0:
-> 2984 return int(np.floor(length / size))
2985 else:
2986 return 2**31 - 1
ValueError: cannot convert float NaN to integer
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/backend_bases.py:2249, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2246 # we do this instead of `self.figure.draw_without_rendering`
2247 # so that we can inject the orientation
2248 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2249 self.figure.draw(renderer)
2250 else:
2251 renderer = None
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:94, in _finalize_rasterization.<locals>.draw_wrapper(artist, renderer, *args, **kwargs)
92 @wraps(draw)
93 def draw_wrapper(artist, renderer, *args, **kwargs):
---> 94 result = draw(artist, renderer, *args, **kwargs)
95 if renderer._rasterizing:
96 renderer.stop_rasterizing()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/figure.py:3282, in Figure.draw(self, renderer)
3279 # ValueError can occur when resizing a window.
3281 self.patch.draw(renderer)
-> 3282 mimage._draw_list_compositing_images(
3283 renderer, self, artists, self.suppressComposite)
3285 renderer.close_group('figure')
3286 finally:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/image.py:133, in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
131 if not_composite or not has_images:
132 for a in artists:
--> 133 a.draw(renderer)
134 else:
135 # Composite any adjacent images together
136 image_group = []
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/artist.py:71, in allow_rasterization.<locals>.draw_wrapper(artist, renderer)
68 if artist.get_agg_filter() is not None:
69 renderer.start_filter()
---> 71 return draw(artist, renderer)
72 finally:
73 if artist.get_agg_filter() is not None:
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3314, in _AxesBase.draw(self, renderer)
3311 for spine in self.spines.values():
3312 artists.remove(spine)
-> 3314 self._update_title_position(renderer)
3316 if not self.axison:
3317 for _axis in self._axis_map.values():
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axes/_base.py:3258, in _AxesBase._update_title_position(self, renderer)
3256 if title.get_text():
3257 for ax in axs:
-> 3258 ax.yaxis.get_tightbbox(renderer) # update offsetText
3259 if ax.yaxis.offsetText.get_text():
3260 bb = ax.yaxis.offsetText.get_tightbbox(renderer)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1425, in Axis.get_tightbbox(self, renderer, for_layout_only)
1423 if renderer is None:
1424 renderer = self.get_figure(root=True)._get_renderer()
-> 1425 ticks_to_draw = self._update_ticks()
1427 self._update_label_position(renderer)
1429 # go back to just this axis's tick labels
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1344, in Axis._update_ticks(self)
1340 # Check if major ticks should be computed.
1341 # Skip if using NullLocator or if all visible components are off.
1342 if (self._tick_group_visible(self._major_tick_kw)
1343 and not isinstance(self.get_major_locator(), NullLocator)):
-> 1344 major_locs = self.get_majorticklocs()
1345 major_labels = self.major.formatter.format_ticks(major_locs)
1346 major_ticks = self.get_major_ticks(len(major_locs))
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:1673, in Axis.get_majorticklocs(self)
1671 def get_majorticklocs(self):
1672 """Return this Axis' major tick locations in data coordinates."""
-> 1673 return self.major.locator()
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2299, in MaxNLocator.__call__(self)
2297 def __call__(self):
2298 vmin, vmax = self.axis.get_view_interval()
-> 2299 return self.tick_values(vmin, vmax)
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2307, in MaxNLocator.tick_values(self, vmin, vmax)
2304 vmin = -vmax
2305 vmin, vmax = mtransforms._nonsingular(
2306 vmin, vmax, expander=1e-13, tiny=1e-14)
-> 2307 locs = self._raw_ticks(vmin, vmax)
2309 prune = self._prune
2310 if prune == 'lower':
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/ticker.py:2237, in MaxNLocator._raw_ticks(self, vmin, vmax)
2235 if self._nbins == 'auto':
2236 if self.axis is not None:
-> 2237 nbins = np.clip(self.axis.get_tick_space(),
2238 max(1, self._min_n_ticks - 1), 9)
2239 else:
2240 nbins = 9
File ~/checkouts/readthedocs.org/user_builds/wradlib/conda/2.9.0/lib/python3.13/site-packages/matplotlib/axis.py:2984, in YAxis.get_tick_space(self)
2982 size = self._get_tick_label_size('y') * 2
2983 if size > 0:
-> 2984 return int(np.floor(length / size))
2985 else:
2986 return 2**31 - 1
ValueError: cannot convert float NaN to integer
<Figure size 1800x500 with 6 Axes>
Compositing#
Before compositing we combine the three radar grids as well as the quality grids into one Dataset, respectively.
radars = xr.DataArray(gtree.children, dims="radar")
radargrids = xr.concat([gtree[radar].ds.DBZH for radar in gtree.children], dim=radars)
# normalizing Quality between 1. and 0.
qualitygrids = xr.concat([1. - (gtree[radar].ds.QUAL / gtree[radar].ds.QUAL.max()) for radar in gtree.children], dim=radars)
display(radargrids)
display(qualitygrids)
<xarray.DataArray 'DBZH' (radar: 3, y: 1000, x: 1000)> Size: 24MB
dask.array<concatenate, shape=(3, 1000, 1000), dtype=float64, chunksize=(1, 1000, 1000), chunktype=numpy.ndarray>
Coordinates:
* radar (radar) <U3 36B 'jab' 'wid' 'hel'
longitude (radar) float64 24B 3.064 5.506 5.406
latitude (radar) float64 24B 51.19 49.91 51.07
altitude (radar) float64 24B 50.0 590.0 140.0
* y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.987e+06 5.988e+06
* x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.991e+05 4.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
crs_wkt int64 8B 0
Attributes:
_Undetect: 0.0
units: dBZ
standard_name: radar_equivalent_reflectivity_factor_h
long_name: Equivalent reflectivity factor H<xarray.DataArray 'QUAL' (radar: 3, y: 1000, x: 1000)> Size: 24MB
array([[[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
...,
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan]],
[[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
...,
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan]],
[[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
...,
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan],
[nan, nan, nan, ..., nan, nan, nan]]], shape=(3, 1000, 1000))
Coordinates:
* radar (radar) <U3 36B 'jab' 'wid' 'hel'
longitude (radar) float64 24B 3.064 5.506 5.406
latitude (radar) float64 24B 51.19 49.91 51.07
altitude (radar) float64 24B 50.0 590.0 140.0
* y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.987e+06 5.988e+06
* x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.991e+05 4.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
crs_wkt int64 8B 0
Attributes:
units: meters
standard_name: projection_range_coordinate
long_name: range_to_measurement_volume
axis: radial_range_coordinate
meters_between_gates: 500.0
spacing_is_constant: true
meters_to_center_of_first_gate: 250.0Then we finally can call wradlib.comp.CompMethods.compose_weighted to create the final output.
composite = radargrids.wrl.comp.compose_weighted(qualitygrids)
display(composite)
<xarray.DataArray 'DBZH' (y: 1000, x: 1000)> Size: 8MB
dask.array<where, shape=(1000, 1000), dtype=float64, chunksize=(1000, 1000), chunktype=numpy.ndarray>
Coordinates:
* y (y) float64 8kB 5.285e+06 5.286e+06 ... 5.987e+06 5.988e+06
* x (x) float64 8kB -2.143e+05 -2.136e+05 ... 4.991e+05 4.999e+05
sweep_mode <U20 80B 'azimuth_surveillance'
crs_wkt int64 8B 0
Attributes:
_Undetect: 0.0
units: dBZ
standard_name: radar_equivalent_reflectivity_factor_h
long_name: Equivalent reflectivity factor HPlot Result#
composite.where(composite>0.1).plot(cmap="HomeyerRainbow", vmin=0, vmax=60)
<matplotlib.collections.QuadMesh at 0x7af7a0ae8410>