Skip to content

Commit 4783f35

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fix/allow_lazy
* upstream/master: minor lint tweaks (pydata#3429) Hack around pydata#3440 (pydata#3442) Update Terminology page to account for multidimensional coordinates (pydata#3410) Use cftime master for upstream-dev build (pydata#3439)
2 parents 9d85efe + 652dd3c commit 4783f35

18 files changed

+56
-67
lines changed

ci/azure/install.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ steps:
1616
--pre \
1717
--upgrade \
1818
matplotlib \
19-
pandas \
19+
pandas=0.26.0.dev0+628.g03c1a3db2 \ # FIXME https://github.com/pydata/xarray/issues/3440
2020
scipy
2121
# numpy \ # FIXME https://github.com/pydata/xarray/issues/3409
2222
pip install \
@@ -25,8 +25,7 @@ steps:
2525
git+https://github.com/dask/dask \
2626
git+https://github.com/dask/distributed \
2727
git+https://github.com/zarr-developers/zarr \
28-
git+https://github.com/Unidata/cftime.git@refs/pull/127/merge
29-
# git+https://github.com/Unidata/cftime # FIXME PR 127 not merged yet
28+
git+https://github.com/Unidata/cftime
3029
condition: eq(variables['UPSTREAM_DEV'], 'true')
3130
displayName: Install upstream dev dependencies
3231

doc/contributing.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,12 +286,12 @@ How to build the *xarray* documentation
286286
Requirements
287287
~~~~~~~~~~~~
288288
Make sure to follow the instructions on :ref:`creating a development environment above <contributing.dev_env>`, but
289-
to build the docs you need to use the environment file ``doc/environment.yml``.
289+
to build the docs you need to use the environment file ``ci/requirements/doc.yml``.
290290

291291
.. code-block:: none
292292
293293
# Create and activate the docs environment
294-
conda env create -f doc/environment.yml
294+
conda env create -f ci/requirements/doc.yml
295295
conda activate xarray-docs
296296
297297
# or with older versions of Anaconda:

doc/terminology.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ Terminology
2727

2828
----
2929

30-
**Coordinate:** An array that labels a dimension of another ``DataArray``. Loosely, the coordinate array's values can be thought of as tick labels along a dimension. There are two types of coordinate arrays: *dimension coordinates* and *non-dimension coordinates* (see below). A coordinate named ``x`` can be retrieved from ``arr.coords[x]``. A ``DataArray`` can have more coordinates than dimensions because a single dimension can be assigned multiple coordinate arrays. However, only one coordinate array can be a assigned as a particular dimension's dimension coordinate array. As a consequence, ``len(arr.dims) <= len(arr.coords)`` in general.
30+
**Coordinate:** An array that labels a dimension or set of dimensions of another ``DataArray``. In the usual one-dimensional case, the coordinate array's values can loosely be thought of as tick labels along a dimension. There are two types of coordinate arrays: *dimension coordinates* and *non-dimension coordinates* (see below). A coordinate named ``x`` can be retrieved from ``arr.coords[x]``. A ``DataArray`` can have more coordinates than dimensions because a single dimension can be labeled by multiple coordinate arrays. However, only one coordinate array can be a assigned as a particular dimension's dimension coordinate array. As a consequence, ``len(arr.dims) <= len(arr.coords)`` in general.
3131

3232
----
3333

34-
**Dimension coordinate:** A coordinate array assigned to ``arr`` with both a name and dimension name in ``arr.dims``. Dimension coordinates are used for label-based indexing and alignment, like the index found on a :py:class:`pandas.DataFrame` or :py:class:`pandas.Series`. In fact, dimension coordinates use :py:class:`pandas.Index` objects under the hood for efficient computation. Dimension coordinates are marked by ``*`` when printing a ``DataArray`` or ``Dataset``.
34+
**Dimension coordinate:** A one-dimensional coordinate array assigned to ``arr`` with both a name and dimension name in ``arr.dims``. Dimension coordinates are used for label-based indexing and alignment, like the index found on a :py:class:`pandas.DataFrame` or :py:class:`pandas.Series`. In fact, dimension coordinates use :py:class:`pandas.Index` objects under the hood for efficient computation. Dimension coordinates are marked by ``*`` when printing a ``DataArray`` or ``Dataset``.
3535

3636
----
3737

38-
**Non-dimension coordinate:** A coordinate array assigned to ``arr`` with a name in ``arr.dims`` but a dimension name *not* in ``arr.dims``. These coordinate arrays are useful for auxiliary labeling. However, non-dimension coordinates are not indexed, and any operation on non-dimension coordinates that leverages indexing will fail. Printing ``arr.coords`` will print all of ``arr``'s coordinate names, with the assigned dimensions in parentheses. For example, ``coord_name (dim_name) 1 2 3 ...``.
38+
**Non-dimension coordinate:** A coordinate array assigned to ``arr`` with a name in ``arr.coords`` but *not* in ``arr.dims``. These coordinates arrays can be one-dimensional or multidimensional, and they are useful for auxiliary labeling. As an example, multidimensional coordinates are often used in geoscience datasets when :doc:`the data's physical coordinates (such as latitude and longitude) differ from their logical coordinates <examples/multidimensional-coords>`. However, non-dimension coordinates are not indexed, and any operation on non-dimension coordinates that leverages indexing will fail. Printing ``arr.coords`` will print all of ``arr``'s coordinate names, with the corresponding dimension(s) in parentheses. For example, ``coord_name (dim_name) 1 2 3 ...``.
3939

4040
----
4141

doc/whats-new.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ Documentation
5555
:py:meth:`Dataset.resample` and explicitly state that a
5656
datetime-like dimension is required. (:pull:`3400`)
5757
By `Justus Magin <https://github.com/keewis>`_.
58+
- Update the terminology page to address multidimensional coordinates. (:pull:`3410`)
59+
By `Jon Thielen <https://github.com/jthielen>`_.
5860

5961
Internal Changes
6062
~~~~~~~~~~~~~~~~

xarray/backends/h5netcdf_.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def prepare_variable(
245245
dtype=dtype,
246246
dimensions=variable.dims,
247247
fillvalue=fillvalue,
248-
**kwargs
248+
**kwargs,
249249
)
250250
else:
251251
nc4_var = self.ds[name]

xarray/backends/zarr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ def open_zarr(
467467
drop_variables=None,
468468
consolidated=False,
469469
overwrite_encoded_chunks=False,
470-
**kwargs
470+
**kwargs,
471471
):
472472
"""Load and decode a dataset from a Zarr store.
473473

xarray/core/accessor_dt.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,9 @@ def __init__(self, obj):
178178
)
179179
self._obj = obj
180180

181-
def _tslib_field_accessor(name, docstring=None, dtype=None):
181+
def _tslib_field_accessor( # type: ignore
182+
name: str, docstring: str = None, dtype: np.dtype = None
183+
):
182184
def f(self, dtype=dtype):
183185
if dtype is None:
184186
dtype = self._obj.dtype

xarray/core/arithmetic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def __array_ufunc__(self, ufunc, method, *inputs, **kwargs):
7676
dataset_join=dataset_join,
7777
dataset_fill_value=np.nan,
7878
kwargs=kwargs,
79-
dask="allowed"
79+
dask="allowed",
8080
)
8181

8282
# this has no runtime function - these are listed so IDEs know these

xarray/core/coordinates.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ def remap_label_indexers(
367367
indexers: Mapping[Hashable, Any] = None,
368368
method: str = None,
369369
tolerance=None,
370-
**indexers_kwargs: Any
370+
**indexers_kwargs: Any,
371371
) -> Tuple[dict, dict]: # TODO more precise return type after annotations in indexing
372372
"""Remap indexers from obj.coords.
373373
If indexer is an instance of DataArray and it has coordinate, then this coordinate

xarray/core/dataset.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2967,15 +2967,13 @@ def expand_dims(
29672967
for a in axis:
29682968
if a < -result_ndim or result_ndim - 1 < a:
29692969
raise IndexError(
2970-
"Axis {a} is out of bounds of the expanded"
2971-
" dimension size {dim}.".format(
2972-
a=a, v=k, dim=result_ndim
2973-
)
2970+
f"Axis {a} of variable {k} is out of bounds of the "
2971+
f"expanded dimension size {result_ndim}"
29742972
)
29752973

29762974
axis_pos = [a if a >= 0 else result_ndim + a for a in axis]
29772975
if len(axis_pos) != len(set(axis_pos)):
2978-
raise ValueError("axis should not contain duplicate" " values.")
2976+
raise ValueError("axis should not contain duplicate values")
29792977
# We need to sort them to make sure `axis` equals to the
29802978
# axis positions of the result array.
29812979
zip_axis_dim = sorted(zip(axis_pos, dim.items()))
@@ -3131,7 +3129,7 @@ def reorder_levels(
31313129
coord = self._variables[dim]
31323130
index = self.indexes[dim]
31333131
if not isinstance(index, pd.MultiIndex):
3134-
raise ValueError("coordinate %r has no MultiIndex" % dim)
3132+
raise ValueError(f"coordinate {dim} has no MultiIndex")
31353133
new_index = index.reorder_levels(order)
31363134
variables[dim] = IndexVariable(coord.dims, new_index)
31373135
indexes[dim] = new_index

xarray/core/indexing.py

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ def _sanitize_slice_element(x):
5959
if isinstance(x, np.ndarray):
6060
if x.ndim != 0:
6161
raise ValueError(
62-
"cannot use non-scalar arrays in a slice for "
63-
"xarray indexing: {}".format(x)
62+
f"cannot use non-scalar arrays in a slice for xarray indexing: {x}"
6463
)
6564
x = x[()]
6665

@@ -128,9 +127,9 @@ def convert_label_indexer(index, label, index_name="", method=None, tolerance=No
128127
# unlike pandas, in xarray we never want to silently convert a
129128
# slice indexer into an array indexer
130129
raise KeyError(
131-
"cannot represent labeled-based slice indexer for "
132-
"dimension %r with a slice over integer positions; "
133-
"the index is unsorted or non-unique" % index_name
130+
"cannot represent labeled-based slice indexer for dimension "
131+
f"{index_name!r} with a slice over integer positions; the index is "
132+
"unsorted or non-unique"
134133
)
135134

136135
elif is_dict_like(label):
@@ -190,7 +189,7 @@ def convert_label_indexer(index, label, index_name="", method=None, tolerance=No
190189
)
191190
indexer = get_indexer_nd(index, label, method, tolerance)
192191
if np.any(indexer < 0):
193-
raise KeyError("not all values found in index %r" % index_name)
192+
raise KeyError(f"not all values found in index {index_name!r}")
194193
return indexer, new_index
195194

196195

@@ -208,7 +207,7 @@ def get_dim_indexers(data_obj, indexers):
208207
if k not in data_obj.dims and k not in data_obj._level_coords
209208
]
210209
if invalid:
211-
raise ValueError("dimensions or multi-index levels %r do not exist" % invalid)
210+
raise ValueError(f"dimensions or multi-index levels {invalid!r} do not exist")
212211

213212
level_indexers = defaultdict(dict)
214213
dim_indexers = {}
@@ -223,8 +222,8 @@ def get_dim_indexers(data_obj, indexers):
223222
for dim, level_labels in level_indexers.items():
224223
if dim_indexers.get(dim, False):
225224
raise ValueError(
226-
"cannot combine multi-index level indexers "
227-
"with an indexer for dimension %s" % dim
225+
"cannot combine multi-index level indexers with an indexer for "
226+
f"dimension {dim}"
228227
)
229228
dim_indexers[dim] = level_labels
230229

@@ -326,7 +325,7 @@ def tuple(self):
326325
return self._key
327326

328327
def __repr__(self):
329-
return "{}({})".format(type(self).__name__, self.tuple)
328+
return f"{type(self).__name__}({self.tuple})"
330329

331330

332331
def as_integer_or_none(value):
@@ -362,9 +361,7 @@ def __init__(self, key):
362361
k = as_integer_slice(k)
363362
else:
364363
raise TypeError(
365-
"unexpected indexer type for {}: {!r}".format(
366-
type(self).__name__, k
367-
)
364+
f"unexpected indexer type for {type(self).__name__}: {k!r}"
368365
)
369366
new_key.append(k)
370367

@@ -395,20 +392,17 @@ def __init__(self, key):
395392
elif isinstance(k, np.ndarray):
396393
if not np.issubdtype(k.dtype, np.integer):
397394
raise TypeError(
398-
"invalid indexer array, does not have "
399-
"integer dtype: {!r}".format(k)
395+
f"invalid indexer array, does not have integer dtype: {k!r}"
400396
)
401397
if k.ndim != 1:
402398
raise TypeError(
403-
"invalid indexer array for {}, must have "
404-
"exactly 1 dimension: ".format(type(self).__name__, k)
399+
f"invalid indexer array for {type(self).__name__}; must have "
400+
f"exactly 1 dimension: {k!r}"
405401
)
406402
k = np.asarray(k, dtype=np.int64)
407403
else:
408404
raise TypeError(
409-
"unexpected indexer type for {}: {!r}".format(
410-
type(self).__name__, k
411-
)
405+
f"unexpected indexer type for {type(self).__name__}: {k!r}"
412406
)
413407
new_key.append(k)
414408

@@ -439,23 +433,20 @@ def __init__(self, key):
439433
elif isinstance(k, np.ndarray):
440434
if not np.issubdtype(k.dtype, np.integer):
441435
raise TypeError(
442-
"invalid indexer array, does not have "
443-
"integer dtype: {!r}".format(k)
436+
f"invalid indexer array, does not have integer dtype: {k!r}"
444437
)
445438
if ndim is None:
446439
ndim = k.ndim
447440
elif ndim != k.ndim:
448441
ndims = [k.ndim for k in key if isinstance(k, np.ndarray)]
449442
raise ValueError(
450443
"invalid indexer key: ndarray arguments "
451-
"have different numbers of dimensions: {}".format(ndims)
444+
f"have different numbers of dimensions: {ndims}"
452445
)
453446
k = np.asarray(k, dtype=np.int64)
454447
else:
455448
raise TypeError(
456-
"unexpected indexer type for {}: {!r}".format(
457-
type(self).__name__, k
458-
)
449+
f"unexpected indexer type for {type(self).__name__}: {k!r}"
459450
)
460451
new_key.append(k)
461452

@@ -574,9 +565,7 @@ def __setitem__(self, key, value):
574565
self.array[full_key] = value
575566

576567
def __repr__(self):
577-
return "{}(array={!r}, key={!r})".format(
578-
type(self).__name__, self.array, self.key
579-
)
568+
return f"{type(self).__name__}(array={self.array!r}, key={self.key!r})"
580569

581570

582571
class LazilyVectorizedIndexedArray(ExplicitlyIndexedNDArrayMixin):
@@ -627,9 +616,7 @@ def __setitem__(self, key, value):
627616
)
628617

629618
def __repr__(self):
630-
return "{}(array={!r}, key={!r})".format(
631-
type(self).__name__, self.array, self.key
632-
)
619+
return f"{type(self).__name__}(array={self.array!r}, key={self.key!r})"
633620

634621

635622
def _wrap_numpy_scalars(array):

xarray/core/missing.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def __call__(self, x):
7171
self._yi,
7272
left=self._left,
7373
right=self._right,
74-
**self.call_kwargs
74+
**self.call_kwargs,
7575
)
7676

7777

@@ -93,7 +93,7 @@ def __init__(
9393
copy=False,
9494
bounds_error=False,
9595
order=None,
96-
**kwargs
96+
**kwargs,
9797
):
9898
from scipy.interpolate import interp1d
9999

@@ -126,7 +126,7 @@ def __init__(
126126
bounds_error=False,
127127
assume_sorted=assume_sorted,
128128
copy=copy,
129-
**self.cons_kwargs
129+
**self.cons_kwargs,
130130
)
131131

132132

@@ -147,7 +147,7 @@ def __init__(
147147
order=3,
148148
nu=0,
149149
ext=None,
150-
**kwargs
150+
**kwargs,
151151
):
152152
from scipy.interpolate import UnivariateSpline
153153

xarray/core/resample.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def _interpolate(self, kind="linear"):
151151
assume_sorted=True,
152152
method=kind,
153153
kwargs={"bounds_error": False},
154-
**{self._dim: self._full_index}
154+
**{self._dim: self._full_index},
155155
)
156156

157157

xarray/core/rolling.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
from typing import Callable
23

34
import numpy as np
45

@@ -106,7 +107,7 @@ def __repr__(self):
106107
def __len__(self):
107108
return self.obj.sizes[self.dim]
108109

109-
def _reduce_method(name):
110+
def _reduce_method(name: str) -> Callable: # type: ignore
110111
array_agg_func = getattr(duck_array_ops, name)
111112
bottleneck_move_func = getattr(bottleneck, "move_" + name, None)
112113

@@ -453,7 +454,7 @@ def _numpy_or_bottleneck_reduce(
453454
array_agg_func=array_agg_func,
454455
bottleneck_move_func=bottleneck_move_func,
455456
),
456-
**kwargs
457+
**kwargs,
457458
)
458459

459460
def construct(self, window_dim, stride=1, fill_value=dtypes.NA):

xarray/plot/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1+
from .dataset_plot import scatter
12
from .facetgrid import FacetGrid
23
from .plot import contour, contourf, hist, imshow, line, pcolormesh, plot, step
3-
from .dataset_plot import scatter
44

55
__all__ = [
66
"plot",

xarray/plot/facetgrid.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ def map_dataarray_line(
294294
hue=hue,
295295
add_legend=False,
296296
_labels=False,
297-
**kwargs
297+
**kwargs,
298298
)
299299
self._mappables.append(mappable)
300300

@@ -376,7 +376,7 @@ def add_legend(self, **kwargs):
376376
labels=list(self._hue_var.values),
377377
title=self._hue_label,
378378
loc="center right",
379-
**kwargs
379+
**kwargs,
380380
)
381381

382382
self.figlegend = figlegend
@@ -491,7 +491,7 @@ def set_titles(self, template="{coord} = {value}", maxchar=30, size=None, **kwar
491491
rotation=270,
492492
ha="left",
493493
va="center",
494-
**kwargs
494+
**kwargs,
495495
)
496496

497497
# The column titles on the top row
@@ -590,7 +590,7 @@ def _easy_facetgrid(
590590
subplot_kws=None,
591591
ax=None,
592592
figsize=None,
593-
**kwargs
593+
**kwargs,
594594
):
595595
"""
596596
Convenience method to call xarray.plot.FacetGrid from 2d plotting methods

0 commit comments

Comments
 (0)