Skip to content

Commit c246448

Browse files
authored
Merge pull request #823 from DHI/getitem_time
Deprecate time slicing using getitem.
2 parents e43222e + 7e46bae commit c246448

File tree

7 files changed

+83
-68
lines changed

7 files changed

+83
-68
lines changed

docs/user-guide/dataarray.qmd

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,25 @@ da
2929

3030
## {{< fa calendar >}} Temporal selection
3131

32+
A time slice of a DataArray can be selected in several different ways.
33+
3234
```{python}
3335
da.sel(time="1985-08-06 12:00")
3436
```
3537

3638
```{python}
37-
da["1985-8-7":]
39+
da.sel(time=slice("1985-08-06 12:00", "1985-08-06 17:00"))
40+
```
41+
42+
```{python}
43+
da.isel(time=2)
3844
```
3945

46+
```{python}
47+
da.isel(time=range(2, ds.n_timesteps, 2))
48+
```
49+
50+
4051
## {{< fa map >}} Spatial selection
4152
4253
The [`sel`](`mikeio.DataArray.sel`) method finds the nearest element.

docs/user-guide/dataset.qmd

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,20 @@ ds.sel(time="1985-08-06 12:00")
5858
```
5959

6060
```{python}
61-
ds["1985-8-7":]
61+
ds.sel(time=slice("1985-08-06 12:00", "1985-08-06 17:00"))
6262
```
6363

64+
```{python}
65+
ds.isel(time=2)
66+
```
67+
68+
```{python}
69+
ds.isel(time=range(2, ds.n_timesteps, 2))
70+
```
71+
72+
73+
74+
6475
## {{< fa map >}} Spatial selection
6576

6677
The `sel` method finds a single element.

mikeio/dataset/_dataarray.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,24 @@ def __getitem__(self, key: Any) -> "DataArray":
629629
return da
630630

631631
def _getitem_parse_key(self, key: Any) -> Any:
632+
if isinstance(key, str):
633+
warnings.warn(
634+
"Indexing with strings is deprecated. Only integer indexing is allowed. Otherwise use .sel(time=...).",
635+
FutureWarning,
636+
)
637+
if isinstance(key, slice):
638+
if isinstance(key.start, str) or isinstance(key.stop, str):
639+
warnings.warn(
640+
"Indexing with strings is deprecated. Only integer indexing is allowed. Otherwise use .sel(time=...).",
641+
FutureWarning,
642+
)
643+
if isinstance(key, Iterable):
644+
if any([isinstance(k, str) for k in key]):
645+
warnings.warn(
646+
"Indexing with strings is deprecated. Only integer indexing is allowed. Otherwise use .sel(time=...).",
647+
FutureWarning,
648+
)
649+
632650
key = key if isinstance(key, tuple) else (key,)
633651
if len(key) > len(self.dims):
634652
raise IndexError(

mikeio/dataset/_dataset.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,10 @@ def __getitem__(self, key: Any) -> DataArray | "Dataset":
740740
time_steps = _get_time_idx_list(self.time, key)
741741
if _n_selected_timesteps(self.time, time_steps) == 0:
742742
raise IndexError("No timesteps found!")
743+
warnings.warn(
744+
"Subsetting in time using indexing is deprecated. Use .sel(time=...) or .isel(time=...) instead.",
745+
FutureWarning,
746+
)
743747
return self.isel(time=time_steps)
744748
if isinstance(key, slice):
745749
if self._is_slice_time_slice(key):
@@ -748,6 +752,11 @@ def __getitem__(self, key: Any) -> DataArray | "Dataset":
748752
time_steps = list(range(s.start, s.stop))
749753
except ValueError:
750754
time_steps = list(range(*key.indices(len(self.time))))
755+
# deprecated, use sel instead or isel instead
756+
warnings.warn(
757+
"Subsetting in time using indexing is deprecated. Use .sel(time=...) or .isel(time=...) instead.",
758+
FutureWarning,
759+
)
751760
return self.isel(time=time_steps)
752761

753762
if self._multi_indexing_attempted(key):

tests/test_consistency.py

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,6 @@ def test_read_dfs_time_selection_str() -> None:
258258
assert all(dsr.time == dssel.time)
259259
assert dsr.shape == dssel.shape
260260

261-
dsgetitem = ds[time]
262-
assert all(dsr.time == dsgetitem.time)
263-
assert dsr.shape == dsgetitem.shape
264-
265261

266262
def test_open_dfs_repr() -> None:
267263
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -286,10 +282,6 @@ def test_read_dfs_time_selection_str_specific() -> None:
286282
assert all(dsr.time == dssel.time)
287283
assert dsr.shape == dssel.shape
288284

289-
dsgetitem = ds[time]
290-
assert all(dsr.time == dsgetitem.time)
291-
assert dsr.shape == dsgetitem.shape
292-
293285

294286
def test_read_dfs_time_selection_list_str() -> None:
295287
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -304,10 +296,6 @@ def test_read_dfs_time_selection_list_str() -> None:
304296
assert all(dsr.time == dssel.time)
305297
assert dsr.shape == dssel.shape
306298

307-
dsgetitem = ds[time]
308-
assert all(dsr.time == dsgetitem.time)
309-
assert dsr.shape == dsgetitem.shape
310-
311299

312300
def test_read_dfs_time_selection_pdTimestamp() -> None:
313301
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -323,10 +311,6 @@ def test_read_dfs_time_selection_pdTimestamp() -> None:
323311
assert all(dsr.time == dssel.time)
324312
assert dsr.shape == dssel.shape
325313

326-
dsgetitem = ds[time]
327-
assert all(dsr.time == dsgetitem.time)
328-
assert dsr.shape == dsgetitem.shape
329-
330314

331315
def test_read_dfs_time_selection_pdDatetimeIndex() -> None:
332316
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -341,10 +325,6 @@ def test_read_dfs_time_selection_pdDatetimeIndex() -> None:
341325
assert all(dsr.time == dssel.time)
342326
assert dsr.shape == dssel.shape
343327

344-
dsgetitem = ds[time]
345-
assert all(dsr.time == dsgetitem.time)
346-
assert dsr.shape == dsgetitem.shape
347-
348328

349329
def test_read_dfs_time_selection_datetime() -> None:
350330
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -360,10 +340,6 @@ def test_read_dfs_time_selection_datetime() -> None:
360340
assert all(dsr.time == dssel.time)
361341
assert dsr.shape == dssel.shape
362342

363-
dsgetitem = ds[time]
364-
assert all(dsr.time == dsgetitem.time)
365-
assert dsr.shape == dsgetitem.shape
366-
367343
dsr2 = mikeio.read(filename=filename, time=pd.Timestamp(time))
368344
assert all(dsr2.time == dsr.time)
369345
assert dsr2.shape == dsr.shape
@@ -382,10 +358,6 @@ def test_read_dfs_time_list_datetime() -> None:
382358
assert all(dsr.time == dssel.time)
383359
assert dsr.shape == dssel.shape
384360

385-
dsgetitem = ds[time]
386-
assert all(dsr.time == dsgetitem.time)
387-
assert dsr.shape == dsgetitem.shape
388-
389361

390362
def test_read_dfs_time_slice_datetime() -> None:
391363
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -400,10 +372,6 @@ def test_read_dfs_time_slice_datetime() -> None:
400372
assert all(dsr.time == dssel.time)
401373
assert dsr.shape == dssel.shape
402374

403-
dsgetitem = ds[time]
404-
assert all(dsr.time == dsgetitem.time)
405-
assert dsr.shape == dsgetitem.shape
406-
407375

408376
def test_read_dfs_time_slice_str() -> None:
409377
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -418,10 +386,6 @@ def test_read_dfs_time_slice_str() -> None:
418386
assert all(dsr.time == dssel.time)
419387
assert dsr.shape == dssel.shape
420388

421-
dsgetitem = ds[time]
422-
assert all(dsr.time == dsgetitem.time)
423-
assert dsr.shape == dsgetitem.shape
424-
425389

426390
def test_read_dfs_time_selection_str_slice() -> None:
427391
extensions = ["dfs0", "dfs2", "dfs1", "dfs0"]
@@ -437,10 +401,6 @@ def test_read_dfs_time_selection_str_slice() -> None:
437401
assert all(dsr.time == dssel.time)
438402
assert dsr.shape == dssel.shape
439403

440-
dsgetitem = ds[time]
441-
assert all(dsr.time == dsgetitem.time)
442-
assert dsr.shape == dsgetitem.shape
443-
444404

445405
def test_read_dfs_time_int() -> None:
446406
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -456,11 +416,6 @@ def test_read_dfs_time_int() -> None:
456416
assert all(dsr.time == dssel.time)
457417
assert dsr.shape == dssel.shape
458418

459-
# integer time selection for DataArray (not Dataset)
460-
dsgetitem = ds[0][time]
461-
assert all(dsr[0].time == dsgetitem.time)
462-
assert dsr[0].shape == dsgetitem.shape
463-
464419

465420
def test_read_dfs_time_list_int() -> None:
466421
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -475,11 +430,6 @@ def test_read_dfs_time_list_int() -> None:
475430
assert all(dsr.time == dssel.time)
476431
assert dsr.shape == dssel.shape
477432

478-
# integer time selection for DataArray (not Dataset)
479-
dsgetitem = ds[0][time]
480-
assert all(dsr[0].time == dsgetitem.time)
481-
assert dsr[0].shape == dsgetitem.shape
482-
483433

484434
def test_read_dfs_time_slice_int() -> None:
485435
extensions = ["dfsu", "dfs2", "dfs1", "dfs0"]
@@ -531,7 +481,7 @@ def test_filter_items_dfs0() -> None:
531481
def test_filter_items_wildcard_getitem() -> None:
532482
dsall = mikeio.read("tests/testdata/sw_points.dfs0")
533483

534-
ds = dsall["*Height*"]
484+
ds = dsall["*Height*"] # type: ignore
535485
assert ds.n_items == 12
536486

537487

@@ -543,7 +493,7 @@ def test_filter_items_dfsu() -> None:
543493
def test_filter_items_dfsu_getitem() -> None:
544494
dsall = mikeio.read("tests/testdata/wind_north_sea.dfsu")
545495
ds = dsall["*direction*"]
546-
assert ds.n_items == 1
496+
assert ds.n_items == 1 # type: ignore
547497
assert "direction" in ds[0].name
548498

549499

tests/test_dataarray.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -549,20 +549,25 @@ def test_dataarray_grid3d_indexing() -> None:
549549
def test_dataarray_getitem_time(da_grid2d: DataArray) -> None:
550550
da = da_grid2d
551551
# time=pd.date_range("2000-01-01", freq="h", periods=10)
552-
da_sel = da["2000-1-1"]
552+
# deprecated use .sel(time=...) or .isel(time=...) instead
553+
with pytest.warns(FutureWarning, match="string"):
554+
da_sel = da["2000-1-1"]
553555
assert da_sel.n_timesteps == da.n_timesteps
554556
assert da_sel.is_equidistant
555557

556-
da_sel = da["2000-1-1 02:00":"2000-1-1 05:00"] # type: ignore
558+
with pytest.warns(FutureWarning, match="string"):
559+
da_sel = da["2000-1-1 02:00":"2000-1-1 05:00"] # type: ignore
557560
assert da_sel.n_timesteps == 4
558561
assert da_sel.is_equidistant
559562

560563
time = ["2000-1-1 02:00", "2000-1-1 04:00", "2000-1-1 06:00"]
561-
da_sel = da[time]
564+
with pytest.warns(FutureWarning, match="string"):
565+
da_sel = da[time]
562566
assert da_sel.n_timesteps == 3
563567
assert da_sel.is_equidistant
564568

565569
time = [da.time[0], da.time[1], da.time[3], da.time[7]]
570+
# TODO should this type of indexing be allowed?
566571
da_sel = da[time]
567572
assert da_sel.n_timesteps == 4
568573
assert not da_sel.is_equidistant

tests/test_dataset.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -163,25 +163,32 @@ def test_index_with_attribute() -> None:
163163

164164
def test_getitem_time(ds3: Dataset) -> None:
165165
# time = pd.date_range("2000-1-2", freq="h", periods=100)
166-
ds_sel = ds3["2000-1-2"]
166+
167+
# deprecated use .sel(time=...) or .isel(time=...) instead
168+
with pytest.warns(FutureWarning, match="time"):
169+
ds_sel = ds3["2000-1-2"] # type: ignore
167170
assert ds_sel.n_timesteps == 24
168171
assert ds_sel.is_equidistant
169172

170-
ds_sel = ds3["2000-1-2":"2000-1-3 00:00"] # type: ignore
173+
with pytest.warns(FutureWarning, match="time"):
174+
ds_sel = ds3["2000-1-2":"2000-1-3 00:00"] # type: ignore
171175
assert ds_sel.n_timesteps == 25
172176
assert ds_sel.is_equidistant
173177

174-
time = ["2000-1-2 04:00:00", "2000-1-2 08:00:00", "2000-1-2 12:00:00"]
175-
ds_sel = ds3[time]
178+
with pytest.warns(FutureWarning, match="time"):
179+
time = ["2000-1-2 04:00:00", "2000-1-2 08:00:00", "2000-1-2 12:00:00"]
180+
ds_sel = ds3[time] # type: ignore
176181
assert ds_sel.n_timesteps == 3
177182
assert ds_sel.is_equidistant
178183

179-
time = [ds3.time[0], ds3.time[1], ds3.time[7], ds3.time[23]]
180-
ds_sel = ds3[time]
184+
with pytest.warns(FutureWarning, match="time"):
185+
time = [ds3.time[0], ds3.time[1], ds3.time[7], ds3.time[23]]
186+
ds_sel = ds3[time] # type: ignore
181187
assert ds_sel.n_timesteps == 4
182188
assert not ds_sel.is_equidistant
183189

184-
ds_sel = ds3[ds3.time[:10]]
190+
with pytest.warns(FutureWarning, match="time"):
191+
ds_sel = ds3[ds3.time[:10]] # type: ignore
185192
assert ds_sel.n_timesteps == 10
186193
assert ds_sel.is_equidistant
187194

@@ -278,18 +285,22 @@ def test_temporal_subset_fancy() -> None:
278285
assert ds.time[0].hour == 0
279286
assert ds.time[-1].hour == 0
280287

281-
selds = ds["2000-01-01 00:00":"2000-01-02 00:00"] # type: ignore
288+
with pytest.warns(FutureWarning, match="time"):
289+
selds = ds["2000-01-01 00:00":"2000-01-02 00:00"] # type: ignore
282290

283291
assert len(selds) == 2
284292
assert selds["Foo"].shape == (25, 100, 30)
285293

286-
selds = ds[:"2000-01-02 00:00"] # type: ignore
294+
with pytest.warns(FutureWarning, match="time"):
295+
selds = ds[:"2000-01-02 00:00"] # type: ignore
287296
assert selds["Foo"].shape == (25, 100, 30)
288297

289-
selds = ds["2000-01-31 00:00":] # type: ignore
298+
with pytest.warns(FutureWarning, match="time"):
299+
selds = ds["2000-01-31 00:00":] # type: ignore
290300
assert selds["Foo"].shape == (25, 100, 30)
291301

292-
selds = ds["2000-01-30":] # type: ignore
302+
with pytest.warns(FutureWarning, match="time"):
303+
selds = ds["2000-01-30":] # type: ignore
293304
assert selds["Foo"].shape == (49, 100, 30)
294305

295306

0 commit comments

Comments
 (0)