Skip to content

Plotting in 2D with one non-dimension coordinate given behaves contrary to documentation and can cause cryptic ValueError #4702

Open
@stanwest

Description

@stanwest

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions