Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
db09c30
ENH: add xarray-native open_datatree with engine= parameter
aladinor Feb 20, 2026
51116af
FIX: integrate optional_groups parameter and fix read-only array bug
aladinor Feb 26, 2026
9ac5f14
STY: apply black formatting to notebook
aladinor Feb 26, 2026
77ce5a7
FIX: resolve rebase conflicts and fix critical bugs in open_datatree
aladinor Mar 31, 2026
4c75c53
ENH: convert all backends to open_datatree with engine= parameter
aladinor Mar 31, 2026
7c5e157
ENH: convert UF backend and fix remaining bugs (Phase 3)
aladinor Mar 31, 2026
44b05b6
DOC: add PR #335 entry to changelog
aladinor Mar 31, 2026
d78db07
STY: apply black formatting to 6 backend files
aladinor Mar 31, 2026
caf1937
fix(nexrad): translate legacy site_coords kwarg in datatree wrapper
aladinor May 12, 2026
391ad60
feat(cfradial2): convert to xarray BackendEntrypoint with engine="cfr…
aladinor May 12, 2026
feae3e9
feat(imd): expose CfRadial2 DataTree via engine="imd" (single-file)
aladinor May 12, 2026
9d0cca9
docs(open-datatree-engine): migrate to MyST + cover all 13 engines
aladinor May 12, 2026
1f1edfb
test(open-datatree-engine): broaden parametrized coverage to cfradial…
aladinor May 12, 2026
f832263
docs(open-datatree-engine): document every BackendEntrypoint method
aladinor May 12, 2026
07709da
fix(io): final-audit regressions in odim/uf/hpl/cfradial1 wrappers
aladinor May 12, 2026
db24741
fix(tests): align Furuno sweep variable count with all other backends…
aladinor May 12, 2026
9830e01
docs(notebooks): migrate all notebooks to xd.open_datatree(engine="...")
aladinor May 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,17 @@
autosummary_generate = rst_files
autoclass_content = "both"

# Render `open_groups_as_dict`, `open_datatree`, and `open_dataset` method
# docstrings on each BackendEntrypoint class. Without `members: True` the
# class page only shows the class-level docstring and class members get
# silently dropped — see `xradar/io/backends/common.py:_compose_docstring`
# for the per-method blocks that need rendering.
autodoc_default_options = {
"members": True,
"undoc-members": False,
"show-inheritance": True,
}

# The version info for the project you're documenting, acts as replacement
# for |version| and |release|, also used in various other places throughout
# the built documents.
Expand Down
1 change: 1 addition & 0 deletions docs/history.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Development

* ENH: Add xarray-native ``open_datatree`` with ``engine=`` parameter for all 13 backends (odim, cfradial1, cfradial2, nexradlevel2, gamic, iris, furuno, rainbow, datamet, hpl, metek, uf, imd), enabling ``xd.open_datatree(file, engine="odim")`` and ``xr.open_datatree(file, engine="odim")``. Legacy ``open_*_datatree()`` functions emit ``FutureWarning`` and delegate to the new entry points; ``xd.io.open_imd_datatree([files])`` remains the documented exception for multi-file IMD volumes. Also adds public ``xd.io.list_engines()`` for engine discovery, NumPy-style docstrings on every ``BackendEntrypoint.open_groups_as_dict`` / ``open_datatree`` method, and a demo notebook covering all 13 engines ({issue}`329`, {pull}`335`) by [@aladinor](https://github.com/aladinor)
* FIX: ensure `to_cfradial2` correctly selects the default storage engine when none is provided, ({pull}`378`) by [@chfer](https://github.com/chfer)
* MNT: Add ``cfradial1_sgp_file`` session fixture and refactor 8 tests in ``test_util.py``/``test_accessors.py`` to share it instead of inlining ``DATASETS.fetch("sample_sgp_data.nc")``. Fixture returns the filename so each test opens its own DataTree, avoiding cross-test mutation ({issue}`346`, {pull}`347`) by [@aladinor](https://github.com/aladinor)
* FIX: IRIS reader rotates the first-loaded moment in each sweep by 1 ray — ``IrisRawFile._get_ray_record_offsets_and_data`` initialised ``j = -1`` so the first matching ray of the first-loaded moment was written to ``raw_data[-1]``; affects files without ``DB_XHDR`` (data-type bit 0) where ``DB_DBT`` becomes the rotated moment ({issue}`357`, {pull}`375`) by [@aladinor](https://github.com/aladinor)
Expand Down
4 changes: 2 additions & 2 deletions docs/notebooks/Assign_GeoCoords.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ file2 = DATASETS.fetch("cfrad.20211011_201557.188_to_20211011_201617.720_DOW8_PP
**Note:** Station coordinates (`latitude`, `longitude`, `altitude`) are stored on the root node of the DataTree. When accessing a sweep dataset directly, use `.to_dataset(inherit="all_coords")` to inherit these coordinates from the root. The `.xradar.georeference()` accessor handles this automatically.

```{code-cell}
dtree1 = xd.io.open_cfradial1_datatree(file1)
dtree1 = xd.open_datatree(file1, engine="cfradial1")
```

```{code-cell}
Expand Down Expand Up @@ -131,7 +131,7 @@ plt.show()
## Example #2

```{code-cell}
dtree2 = xd.io.open_cfradial1_datatree(file2)
dtree2 = xd.open_datatree(file2, engine="cfradial1")
```

```{code-cell}
Expand Down
9 changes: 4 additions & 5 deletions docs/notebooks/CfRadial1.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,11 @@ display(ds)
The same works analoguous with the datatree loader. But additionally we can provide a sweep number or list.

```{code-cell}
?xd.io.open_cfradial1_datatree
?xd.open_datatree
```

```{code-cell}
dtree = xd.io.open_cfradial1_datatree(
filename,
dtree = xd.open_datatree(filename, engine="cfradial1",
first_dim="time",
optional=False,
)
Expand All @@ -109,11 +108,11 @@ dtree["sweep_0"].ds.DBZ.sortby("azimuth").plot(y="azimuth")
```

```{code-cell}
dtree = xd.io.open_cfradial1_datatree(filename, sweep=[0, 1, 8])
dtree = xd.open_datatree(filename, engine="cfradial1", sweep=[0, 1, 8])
display(dtree)
```

```{code-cell}
dtree = xd.io.open_cfradial1_datatree(filename, sweep=["sweep_0", "sweep_4", "sweep_8"])
dtree = xd.open_datatree(filename, engine="cfradial1", sweep=["sweep_0", "sweep_4", "sweep_8"])
display(dtree)
```
2 changes: 1 addition & 1 deletion docs/notebooks/CfRadial1_Export.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ filename = DATASETS.fetch("cfrad.20080604_002217_000_SPOL_v36_SUR.nc")
```

```{code-cell}
radar = xd.io.open_cfradial1_datatree(filename, first_dim="auto")
radar = xd.open_datatree(filename, engine="cfradial1", first_dim="auto")
display(radar)
```

Expand Down
4 changes: 2 additions & 2 deletions docs/notebooks/CfRadial1_Model_Transformation.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ xradar provides two easy ways to retrieve the CfRadial1 data as CfRadial2 groups
This is the most complete representation as a DataTree. All groups and subgroups are represented in a tree-like structure. Can be parameterized using kwargs. Easy write to netCDF4.

```{code-cell}
dtree = xd.io.open_cfradial1_datatree(filename, optional_groups=True)
dtree = xd.open_datatree(filename, engine="cfradial1", optional_groups=True)
with xr.set_options(display_expand_data_vars=True, display_expand_attrs=True):
display(dtree)
```
Expand Down Expand Up @@ -247,7 +247,7 @@ for grp in dtree.groups:
#### Roundtrip with `xradar.io.to_cfradial2`

```{code-cell}
dtree3 = xd.io.open_cfradial1_datatree(filename, optional_groups=True)
dtree3 = xd.open_datatree(filename, engine="cfradial1", optional_groups=True)
```

```{code-cell}
Expand Down
2 changes: 1 addition & 1 deletion docs/notebooks/Furuno.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ ds.DBZH.sortby("azimuth").plot(y="azimuth")
Furuno scn/scnx files consist only of one sweep. But we might load and combine several sweeps into one DataTree.

```{code-cell}
dtree = xd.io.open_furuno_datatree(filename_scn)
dtree = xd.open_datatree(filename_scn, engine="furuno")
display(dtree)
```

Expand Down
10 changes: 5 additions & 5 deletions docs/notebooks/GAMIC.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ display(ds)
The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list.

```{code-cell}
help(xd.io.open_gamic_datatree)
help(xd.open_datatree)
```

```{code-cell}
dtree = xd.io.open_gamic_datatree(filename, sweep=8)
dtree = xd.open_datatree(filename, engine="gamic", sweep=8)
display(dtree)
```

Expand All @@ -96,16 +96,16 @@ dtree["sweep_0"].ds.DBZH.plot()
```

```{code-cell}
dtree = xd.io.open_gamic_datatree(filename, sweep="sweep_8")
dtree = xd.open_datatree(filename, engine="gamic", sweep="sweep_8")
display(dtree)
```

```{code-cell}
dtree = xd.io.open_gamic_datatree(filename, sweep=[0, 1, 8])
dtree = xd.open_datatree(filename, engine="gamic", sweep=[0, 1, 8])
display(dtree)
```

```{code-cell}
dtree = xd.io.open_gamic_datatree(filename, sweep=["sweep_1", "sweep_2", "sweep_8"])
dtree = xd.open_datatree(filename, engine="gamic", sweep=["sweep_1", "sweep_2", "sweep_8"])
display(dtree)
```
2 changes: 1 addition & 1 deletion docs/notebooks/Georeference_TargetCRS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import xradar as xd

```{code-cell}
filename = DATASETS.fetch("cfrad.20080604_002217_000_SPOL_v36_SUR.nc")
radar = xd.io.open_cfradial1_datatree(filename, first_dim="auto")
radar = xd.open_datatree(filename, engine="cfradial1", first_dim="auto")
radar
```

Expand Down
8 changes: 5 additions & 3 deletions docs/notebooks/HaloPhotonics.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,17 @@ import xradar as xd

Opening a Halo Photonics Doppler lidar .hpl file.

We use the `xd.io.open_hpl_datatree` in order to load the Halo Photonics Doppler lidar data. After that we will need to enter in the latitude and longitude in order to properly georeference the data. The .hpl file does not contain the latitude, longitude, or altitude of the lidar, so these need to be entered in as keywords as a part of the `backend_kwargs` argument to `xd.io.open_hpl_datatree`.
We use `xd.open_datatree(file, engine="hpl")` to load the Halo Photonics Doppler lidar data. The .hpl file does not contain the latitude, longitude, or altitude of the lidar, so those need to be passed as `latitude=`, `longitude=`, and `altitude=` keyword arguments.

In this example, we are using the coordinates of the Doppler lidar at the Nantucket Wastewater Management Facility, deployed as as part of the DOE Energy Efficiency and Renewable Energy Office's [3rd Wind Forecast Improvement Project](https://www2.whoi.edu/site/wfip3/).

```{code-cell}
ds = xd.io.open_hpl_datatree(
ds = xd.open_datatree(
DATASETS.fetch("User1_184_20240601_013257.hpl"),
engine="hpl",
sweep=[0, 1, 2, 3, 4, 5, 6, 7, 8],
backend_kwargs=dict(latitude=41.24276244459537, longitude=-70.1070364814594),
latitude=41.24276244459537,
longitude=-70.1070364814594,
)
```

Expand Down
7 changes: 6 additions & 1 deletion docs/notebooks/IMD.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,17 @@ help(xd.io.open_imd_datatree)
### Single sweep

```{code-cell}
dtree = xd.io.open_imd_datatree(filename_sweep_0)
dtree = xd.open_datatree(filename_sweep_0, engine="imd")
display(dtree)
```

### Volume from multiple files

`xd.open_datatree(..., engine="imd")` takes a single file. To assemble a
full IMD volume from a list of per-sweep files, use the dedicated
`xd.io.open_imd_datatree` function (the documented multi-file carve-out
from the engine API).

```{code-cell}
dtree = xd.io.open_imd_datatree(volume_files)
display(dtree)
Expand Down
11 changes: 5 additions & 6 deletions docs/notebooks/Iris.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,27 +76,26 @@ display(ds)
The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list. The underlying xarray.Dataset can be accessed with property `.ds`.

```{code-cell}
help(xd.io.open_iris_datatree)
help(xd.open_datatree)
```

```{code-cell}
dtree = xd.io.open_iris_datatree(filename_volume)
dtree = xd.open_datatree(filename_volume, engine="iris")
display(dtree)
```

```{code-cell}
dtree = xd.io.open_iris_datatree(filename_volume, sweep="sweep_8")
dtree = xd.open_datatree(filename_volume, engine="iris", sweep="sweep_8")
display(dtree)
```

```{code-cell}
dtree = xd.io.open_iris_datatree(filename_volume, sweep=[1, 2, 8])
dtree = xd.open_datatree(filename_volume, engine="iris", sweep=[1, 2, 8])
display(dtree)
```

```{code-cell}
dtree = xd.io.open_iris_datatree(
filename_volume,
dtree = xd.open_datatree(filename_volume, engine="iris",
sweep=["sweep_0", "sweep_1", "sweep_8"],
)
display(dtree)
Expand Down
4 changes: 2 additions & 2 deletions docs/notebooks/MRR.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ from open_radar_data import DATASETS
import xradar as xd
```

`xd.io.open_metek_datatree` supports the Metek MRR2 processed (.pro, .ave) and raw (.raw) files. The initialized datatree will contain all vertically pointing radar data in one sweep.
`xd.open_datatree(file, engine="metek")` supports the Metek MRR2 processed (.pro, .ave) and raw (.raw) files. The initialized datatree will contain all vertically pointing radar data in one sweep.

In this example, we are loading the 60 s average files from the MRR2 sampling a rain event over the Argonne Testbed for Multiscale Observational Science at Argonne National Laboratory in the Chicago suburbs.

Expand All @@ -34,7 +34,7 @@ decompressed_file = mrr_test_file[:-3]
with gzip.open(mrr_test_file, "rb") as f_in:
with open(decompressed_file, "wb") as f_out:
shutil.copyfileobj(f_in, f_out)
with xd.io.open_metek_datatree(decompressed_file) as ds:
with xd.open_datatree(decompressed_file, engine="metek") as ds:
display(ds)
```

Expand Down
2 changes: 1 addition & 1 deletion docs/notebooks/Mapping_Sweeps.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import xradar as xd
filename = DATASETS.fetch("sample_sgp_data.nc")

# Open the radar file into a DataTree object
dtree = xd.io.open_cfradial1_datatree(filename)
dtree = xd.open_datatree(filename, engine="cfradial1")
dtree = dtree.xradar.georeference()
```

Expand Down
12 changes: 5 additions & 7 deletions docs/notebooks/NexradLevel2.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ display(ds)
The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list.

```{code-cell}
help(xd.io.open_nexradlevel2_datatree)
help(xd.open_datatree)
```

```{code-cell}
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=4)
dtree = xd.open_datatree(filename, engine="nexradlevel2", sweep=4)
display(dtree)
```

Expand All @@ -107,12 +107,12 @@ dtree["sweep_4"].ds.DBZH.plot(cmap="HomeyerRainbow")
```

```{code-cell}
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep="sweep_8")
dtree = xd.open_datatree(filename, engine="nexradlevel2", sweep="sweep_8")
display(dtree)
```

```{code-cell}
dtree = xd.io.open_nexradlevel2_datatree(filename, sweep=[0, 1, 8])
dtree = xd.open_datatree(filename, engine="nexradlevel2", sweep=[0, 1, 8])
display(dtree)
```

Expand All @@ -125,9 +125,7 @@ dtree["sweep_8"]["sweep_fixed_angle"].values
```

```{code-cell}
dtree = xd.io.open_nexradlevel2_datatree(
filename,
)
dtree = xd.open_datatree(filename, engine="nexradlevel2")
display(dtree)
```

Expand Down
10 changes: 5 additions & 5 deletions docs/notebooks/ODIM_H5.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ display(ds)
The same works analoguous with the datatree loader. But additionally we can provide a sweep string, number or list.

```{code-cell}
?xd.io.open_odim_datatree
?xd.open_datatree
```

```{code-cell}
dtree = xd.io.open_odim_datatree(filename, sweep=8)
dtree = xd.open_datatree(filename, engine="odim", sweep=8)
display(dtree)
```

Expand All @@ -100,16 +100,16 @@ dtree["sweep_0"].ds.DBZH.plot()
```

```{code-cell}
dtree = xd.io.open_odim_datatree(filename, sweep="sweep_8")
dtree = xd.open_datatree(filename, engine="odim", sweep="sweep_8")
display(dtree)
```

```{code-cell}
dtree = xd.io.open_odim_datatree(filename, sweep=[0, 1, 8])
dtree = xd.open_datatree(filename, engine="odim", sweep=[0, 1, 8])
display(dtree)
```

```{code-cell}
dtree = xd.io.open_odim_datatree(filename, sweep=["sweep_0", "sweep_1", "sweep_8"])
dtree = xd.open_datatree(filename, engine="odim", sweep=["sweep_0", "sweep_1", "sweep_8"])
display(dtree)
```
Loading
Loading