Plotting in 2D with one non-dimension coordinate given behaves contrary to documentation and can cause cryptic ValueError
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4.2k
- Forks
- 1.4k
- Avg merge
- 2d 15h
- Merged PRs (30d)
- 14
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
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with _infer_xy_labels in xarray/plot/utils.py and the 2-D plotting path in xarray/plot/plot.py. Reproduce the provided DataArray examples, then inspect how omitted coordinates are inferred and how duplicate dimensions reach transpose. Done means valid non-dimension x or y arguments no longer produce the cryptic ValueError, invalid combinations fail clearly, and the plotting documentation describes the inference behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- matplotlib, numpy, python
- Domain
- data-visualization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100