xarray icon indicating copy to clipboard operation
xarray copied to clipboard

Unable to use aspect="equal" in plot.imshow() whereas option is given in the doc

Open aspyk opened this issue 2 years ago • 6 comments

What is your issue?

I'm using the version 2023.12.0.

In the doc of imshow (https://docs.xarray.dev/en/stable/generated/xarray.DataArray.plot.imshow.html) it is written for the aspect parameter:

aspect ("auto", "equal", scalar or None, optional) – Aspect ratio of plot, so that aspect * size gives the width in inches. Only used if a size is provided.

But if I try this simple code:

import xarray as xr
import numpy as np
import matplotlib.pyplot as plt

data_array = np.random.randint(0, 255, size=(3, 2), dtype=np.uint8)
xarray_data = xr.DataArray(data_array, dims=('dim1', 'dim2'))
xarray_data.plot.imshow(size=5, aspect="equal")
plt.show()

I get the following error:

...
  File "...\lib\site-packages\xarray\plot\dataarray_plot.py", line 1598, in newplotfunc
    raise ValueError("plt.imshow's `aspect` kwarg is not available in xarray")
ValueError: plt.imshow's `aspect` kwarg is not available in xarray

Indeed in the code here there is:

        if "imshow" == plotfunc.__name__ and isinstance(aspect, str):
            # forbid usage of mpl strings
            raise ValueError("plt.imshow's `aspect` kwarg is not available in xarray")

which seems quite clear.

So is there something I'm doing wrong or is it an issue between doc and code ? Thanks !

aspyk avatar Jan 07 '24 22:01 aspyk

Thanks for opening your first issue here at xarray! Be sure to follow the issue template! If you have an idea for a solution, we would really welcome a Pull Request with proposed changes. See the Contributing Guide for more. It may take us a while to respond here, but we really value your contribution. Contributors like you help make xarray better. Thank you!

welcome[bot] avatar Jan 07 '24 22:01 welcome[bot]

@aspyk Thanks for raising this. I've followed the code to the PR, where this was introduced: https://github.com/pydata/xarray/pull/1168. It looks like there's a reason to not have aspect forwarded to imshow as a string, so I'm assuming that there is a slight inconsistency with the docstring.

You could still provide the aspect as scalar value (eg. 1.0). I've no detailed knowledge of xarray's plotting, so appreciate comments of others here.

kmuehlbauer avatar Jan 08 '24 06:01 kmuehlbauer

Thanks for your quick answer. I just tried the aspect as scalar value but it doesn't seem to "lock" the aspect ratio, when I resize dynamically the window the aspect ratio follow the resizing and does not keep its initial value :/

aspyk avatar Jan 08 '24 20:01 aspyk

@aspyk Let's wait for some more informed opinions here.

You might use plt.gca().axes.set_aspect('equal', 'box') before show to work around this (no resizing tested). See https://stackoverflow.com/questions/2934878/matplotlib-pyplot-preserve-aspect-ratio-of-the-plot

kmuehlbauer avatar Jan 09 '24 06:01 kmuehlbauer

Thank, it works nice! In my case I have several axis, so I'm ended with this:

ax = xarray_data.plot.imshow()
ax.axes.set_aspect("equal")
plt.show()

Indeed the trick was to apply set_aspect to ax.axes and not only ax...

aspyk avatar Jan 09 '24 13:01 aspyk

Same issue here. After checking the error message and the source code. aspect works differently in xarray and matplotlib. In matplotlib imshow, aspect controls the axis ratio, while in xarray the figure size ratio. That's why xarray raise an error when we try to pass 'equal' to aspect. Xarray did not impl axis ratio control for its imshow, so we have to control by mpl ourself as suggested by @kmuehlbauer

@aspyk Let's wait for some more informed opinions here.

You might use plt.gca().axes.set_aspect('equal', 'box') before show to work around this (no resizing tested). See https://stackoverflow.com/questions/2934878/matplotlib-pyplot-preserve-aspect-ratio-of-the-plot

Xiao-Chenguang avatar May 11 '25 10:05 Xiao-Chenguang