pydata / pydata/xarray

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

Open
#4,702 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

topic-plotting
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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.