Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RuntimeError: adjustable='datalim' is not allowed when both axes are shared. #11416

Closed
nbud opened this issue Jun 11, 2018 · 13 comments · Fixed by #21318
Closed

RuntimeError: adjustable='datalim' is not allowed when both axes are shared. #11416

nbud opened this issue Jun 11, 2018 · 13 comments · Fixed by #21318
Milestone

Comments

@nbud
Copy link

nbud commented Jun 11, 2018

Bug report

Bug summary

Matplotlib 2.2.2 fails to plot the figure described below. The code works with Matplotlib 2.0.2.

The issue seems to be the combination of sharex=True, sharey=True and axis('equal').

Code for reproduction

import matplotlib.pyplot as plt
import numpy as np

nrows = 3
ncols = 2
fig, axes = plt.subplots(ncols=ncols, nrows=nrows, sharex=True, sharey=True)

n = 20
np.random.seed(1234)
data = np.random.uniform(size=(nrows, ncols, n, n))

for i in range(nrows):
    for j in range(ncols):
        ax = axes[i, j]
        ax.imshow(data[i, j])
        ax.axis("equal")

plt.show()

Actual outcome

With Matplotlib 2.2.2, the figure is not drawn and the following exception is raised:

Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\backends\backend_qt5.py", line 519, in _draw_idle
    self.draw()
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py", line 433, in draw
    self.figure.draw(self.renderer)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\figure.py", line 1475, in draw
    renderer, self, artists, self.suppressComposite)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 2546, in draw
    self.apply_aspect()
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 1631, in apply_aspect
    raise RuntimeError("adjustable='datalim' is not allowed when both"
RuntimeError: adjustable='datalim' is not allowed when both axes are shared.

Expected outcome

Drawn figure, no error, as with Matplotlib 2.0.2

Matplotlib version

  • Operating system: Windows 7 64 bits
  • Matplotlib version: 2.2.2
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.6
  • Jupyter version (if applicable):
  • Other libraries: Anaconda 5.2
@jklymak
Copy link
Member

jklymak commented Jun 11, 2018

This was a purposeful change in #10033. However, it should have had an API change entry - our apologies.

I'm also not sure that your use case should error. I think we need to still think about all the sharing/datalim interactions to make sure we always do the right thing.... ping @efiring

@jklymak jklymak added this to the v2.2.3 milestone Jun 11, 2018
@efiring
Copy link
Member

efiring commented Jun 11, 2018

This combination is internally consistent only in the special case where all shared Axes have identical box aspect ratios in screen space. This is a common case, but by no means universal. Rather than blocking datalim at the outset, it might be possible to check for the consistency condition in apply_aspect. If it is met, then apply_aspect might be able to proceed as if there were no sharing. But it can get very complicated, because axes A and B might share both x and y, but C might share only x, etc.

I'm not sure it is worth trying to untangle this web in order to relax the simple blanket restriction against combining sharing of both axes with adjustable datalim. Maybe the only sensible step in that direction would be to handle the single special case in which all sharing involves both x and y in a set of Axes in a single Figure.

Or maybe apply_aspect can be replaced with something based on a general constraint solver, which could raise an exception whenever it runs into a conflict.

@bgriffen
Copy link

I have the same problem as @nbud. It is fairly common to have say a 2x2 grid of images displayed via imshow and you want to preserve the x-y scale after a zoom event say (e.g. R,G,B in three panels then RGB in the fourth). I'll switch back for 2.0.2 in the mean time.

@efiring
Copy link
Member

efiring commented Jun 26, 2018

Have you considered using adjustable='box'?

@jklymak jklymak modified the milestones: v2.2.3, v3.1 Jul 16, 2018
@1fish2
Copy link

1fish2 commented Jul 16, 2018

matplotlib 1.5.3 and 2.2.2 seem in conflict over this, or maybe I just don't understand which way to go.

I'm updating a codebase from matplotlib 1.5.3 to 2.2.2. adjustable='box-forced' is no longer defined so I switched to 'box':

fig, axesList = plt.subplots(n_generation, sharey=True, sharex=True,
    subplot_kw={'aspect': 0.4, 'adjustable': 'box'})

That works in matplotlib 2.2.2 but matplotlib 1.5.3 raises:

ValueError: adjustable must be "datalim" for shared axes

It'd be good for the new code to pass our Jenkins build before I merge in the change and update the shared pyenv to the new libraries, so I tried 'datalim'. Then matplotlib 2.2.2 raises the opposite error:

RuntimeError: adjustable='datalim' is not allowed when both axes are shared.

I don't see docs on these choices and their compatibility with shared axes.

Matplotlib version

  • Operating system: sys.platform = linux2
  • Matplotlib version: 2.2.2
  • Matplotlib backend: Agg
  • Python version: 2.7.15

@jklymak
Copy link
Member

jklymak commented Feb 11, 2019

To me the error here is that ax.axis('equal') calls ax.set_aspect('equal', adjustable='datalim'). Why does it do that instead of the default 'box'?

@efiring
Copy link
Member

efiring commented Feb 11, 2019

I think this is just a matter of leaving long-standing behavior in place. This definition of 'equal' predates the Axes refactoring 6 years ago. (I think it originated in Matlab compatibility.) Most or all of the behavior of ax.axis() has been kept unchanged from early days. There are two arguments that offer variations on 'equal': 'scaled', and 'image'. Both of those use 'box' adjustable.

@jklymak
Copy link
Member

jklymak commented Mar 3, 2019

Anyhow, the workaround is to call ax.set_aspect('equal'). We should probably deprecate ax.axis('equal'), since its hard to see why we need two ways to do the same thing. But I think this can wait for 3.2...

@jklymak jklymak modified the milestones: v3.1.0, v3.2.0 Mar 3, 2019
@ImportanceOfBeingErnest
Copy link
Member

@timhoffm recently updated the docstring of axis("equal") and cohorts in #15032. Would that qualify to close this issue, or is there another action item?

@timhoffm
Copy link
Member

timhoffm commented Sep 7, 2019

#15032 only adds documentation that ax.axis('equal') is ax.set_aspect('equal', adjustable='datalim').

That does not help too much for a user with the above problem because his code does not mention datalim. And the error message does not mention aspect/equal. Any idea how to hint at a solution in the error message without assuming too much?

@tacaswell tacaswell modified the milestones: v3.2.0, needs sorting Sep 10, 2019
@stormshawn
Copy link

I agree with @timhoffm. I am getting the same error and my code doesn't mention datalim

@jklymak
Copy link
Member

jklymak commented Oct 8, 2021

@stormshawn are you using axis('equal') instead of ax.set_aspect('equal')? Is there a compelling reason to do so?

@stormshawn
Copy link

@jklymak I was using set_aspect('equal', adjustable="datalim") and that didn't work so I used set_aspect('equal') and it compiled. Though I'm not sure if that is the solution I should use here.

@QuLogic QuLogic modified the milestones: needs sorting, v3.6.0 Nov 24, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.