Description
What happened:
I called a 2-D plot method with one coordinate specified as a non-dimension coordinate through the x
or y
argument. The method raised a ValueError
that complained about a tuple of duplicate coordinates that I had not provided.
Also, when I specified x
and omitted y
, the method took y
to be the second dimension of the DataArray
.
What you expected to happen:
I expected the unspecified x
or y
argument to behave as when I specified neither argument, so that, for a suitable DataArray
da
, calling da.plot(x="lon")
would have the same Y axis as da.plot()
. That expectation is consistent with the docstring common to 2-D plotting methods, where the default values for the x
and y
arguments are da.dims[1]
and da.dims[0]
, respectively. However, as discussed below, the docstring does not mention that xarray tries to guess the omitted coordinate.
Minimal Complete Verifiable Example:
Executing
import numpy as np
import xarray as xr
da = xr.DataArray(
np.arange(20).reshape(4, 5),
dims=("v", "u"),
coords={"lat": ("v", np.linspace(0, 30, 4)), "lon": ("u", np.linspace(-20, 20, 5))},
)
da.plot(x="lon")
causes (with file paths abbreviated)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "...\xarray\plot\plot.py", line 446, in __call__
return plot(self._da, **kwargs)
File "...\xarray\plot\plot.py", line 200, in plot
return plotfunc(darray, **kwargs)
File "...\xarray\plot\plot.py", line 707, in newplotfunc
darray = darray.transpose(*dims, transpose_coords=True)
File "...\xarray\core\dataarray.py", line 2036, in transpose
dims = tuple(utils.infix_dims(dims, self.dims))
File "...\xarray\core\utils.py", line 725, in infix_dims
raise ValueError(
ValueError: ('u', 'u') must be a permuted list of ('v', 'u'), unless `...` is included
Executing da.plot(y="lon")
causes the same exception.
Anything else we need to know?:
Two aspects of this issue that I see are the behavior and the documentation.
The behavior in the above example involves xarray trying to guess the other dimension [#1291 in v. 0.9.2]. The guessing logic tests whether the given coordinate equals one of the array's dimension names; here, the given coordinate is a non-dimension coordinate and fails to match. When the match fails, the other coordinate is set to the second dimension, whether the given coordinate was x
or y
. One possible improvement would be to set the y
coordinate to the first dimension instead, as in the following replacement for the last line of the guessing logic:
y = darray.dims[1] if x == darray.dims[0] else darray.dims[0]
With that change, da.plot(x="lon")
and da.plot(y="lat")
would succeed and produce the plots I expect, while da.plot(x="lat")
and da.plot(y="lon")
would raise ValueError
. Also, I would find it more helpful if the exception message were more clearly related to the arguments of the call. The _infer_xy_labels
function might need to notice that it was about to set x
and y
to the same dimension name and raise an exception at that point.
The documentation seems not to have been updated for #1291 and does not mention the guessing behavior.
Environment:
Output of xr.show_versions()
INSTALLED VERSIONS
------------------
commit: None
python: 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]
python-bits: 64
OS: Windows
OS-release: 10
machine: AMD64
processor: Intel64 Family 6 Model 94 Stepping 3, GenuineIntel
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: English_United States.1252
libhdf5: 1.10.4
libnetcdf: 4.7.3
xarray: 0.16.1
pandas: 1.1.3
numpy: 1.19.2
scipy: None
netCDF4: 1.5.3
pydap: None
h5netcdf: 0.8.1
h5py: 2.10.0
Nio: None
zarr: None
cftime: 1.3.0
nc_time_axis: None
PseudoNetCDF: None
rasterio: None
cfgrib: None
iris: None
bottleneck: None
dask: 2.30.0
distributed: 2.30.1
matplotlib: 3.3.2
cartopy: None
seaborn: None
numbagg: None
pint: None
setuptools: 50.3.0.post20201006
pip: 20.2.4
conda: None
pytest: None
IPython: 7.18.1
sphinx: None