I am trying to make a bunch of figures on a cluster. In the process of doing so, I have discovered that images are flipped upside down when using tight_layout on GridSpec objects that do not contain the image.
However, this bug only happens when interactive mode is off. Even more strangely, it is not inverted if the figure has already been saved prior to calling tight_layout.
Code for reproduction
importnumpyasnpimportmatplotlib.pyplotaspltfrommatplotlib.gridspecimportGridSpecx, y=np.ogrid[0:6, 0:7]
imdata=x+y# Two column figure (with simple gridspecs for this example)gs_left=GridSpec(1, 1, left=0.05, right=0.48)
gs_right=GridSpec(1, 1, left=0.55, right=0.98)
f=plt.figure()
# Add the image to the right columnim_ax=f.add_subplot(gs_right[0])
im_ax.imshow(imdata, extent= (0, 10, 0, 10), origin='upper', aspect='auto')
# Uncommenting the following line makes both figures correct#f.savefig("image_ok")# Call tight layout on the OTHER grid specgs_left.tight_layout(f, rect= [0.05, 0.05, 0.45, 0.95])
f.savefig("image_inverted")
Actual outcome
The image is inverted. The dark portion of the image should be on the bottom left.
Expected outcome
Matplotlib version
Operating system: Fedora 28
Matplotlib version: 2.2.3
Matplotlib backend: GTK3Cairo, I think maybe agg with non-interactive?
Python version: 3.6.6
Matplotlib was installed from Fedora's package manager.
Thanks for taking a look. The above code reflects when I see this behavior: I add the image to the right gridspec, and call tight_layout on the left. The output images above are from running the script above from my machine, though you are right I forgot to include the line that makes the empty axis in gs_left. When i have the chance I'll also try it on conda python.
@jklymak I do agree that from the documentation, I should need origin='lower' but I have found that at least with interactive mode, I have to use origin = 'upper' to get my desired result.
The above does not show the error. What backend are you using (print(matplotlib.get_backend())? I assume you are calling plt.show or running from ipython, or?
There is a relatively new tutorial about imshow's origin and extent available here. This shows that what is called "actual outcome" above, is indeed expected for extent = (0, 10, 0, 10), origin = 'upper'.
So if anything is wrong, then it would the "expected outcome". And indeed using the cairo backend ("TkCairo" in my case, since I don't have GTK available), the image is inverted.
What then happens seems that if you use tight_layout, cairo backend will for some reason fall back to agg and the expected outcome with the dark color in the upper left corner is produced, together with a warning UserWarning: tight_layout : falling back to Agg renderer.
So in total there are two potential issues:
*Cairo backend mixes up origin = 'lower' and 'upper' (it just reverses their meaning it seems)
tight_layout will fall back to agg for some reason.
My backend is GTK3Cairo. @ImportanceOfBeingErnest is right that I get the agg warning when calling tight from python when interactive mode is off, so given the issues that he mentioned, it seems like cairo images being upside down would explain everything that I've experienced. However, I do not get the agg warning when using interactive mode, and therefore see consistently wrong behavior. To me, the "bug" is mostly that it's inconsistent... I've been pulling my hair out trying to figure out why images in my figures appear one way when plotting them without interactive mode, and are inverted when I use interactive mode. It took my a while to even narrow it down to the tight_layout call.
I've read the tutorial a bunch of times, but it didn't seem to be accurate (didn't know about #8798) so I chalked it up to some version difference or something. I will say that the API for imshow is rather complicated once you start caring about where the image is in an axis.
So it seems like the final verdict is that this is due to #11724 not being backported to my version of matplotlib? Should I close the issue or leave it open as a petition to backport the fix so I don't have to plot twice to get consistently oriented images?
Oh and @jklymak I was looking at the generated file. I get different behavior when I use interactive mode (which I guess is the equivalent of plt.show()?).
This is still confusing. Running the code above as a script should not use gtk3cairo. And the bug in #8798 shouldn’t have anything to do w tight_layout. I’d also have thought that saving interactively should still have run through agg but maybe by that point the image is already incorrect. Anyhow the problem has been fixed in master. I don’t see any reason it couldn’t be back ported to 2.2.4.
I suppose the user's backend rcParam is simply set to gtk3cairo?!
And then, it's a combination of both, I guess. Without the tight_layout you would probably consistently get the wrong behaviour. So appart from the flipping issue, there is also the question why tight_layout would switch the renderer and whether this is expected.
(There is also another warning about tight_layout not being able to process the gridspecs, so I'm not even sure if it would be extected to work in this case.)
@jklymak If I just start a vanilla python shell and look at the backend, it's already gtk3cairo. Poking around, I realized that I had set it to that (and forgot about it) in my matplotlibrc file. Is there a reason to not use that backend? I did mention it as my backend in the original bug report. I just removed the matplotlibrc.
I would definitely appreciate the bug fix being ported! If at all possible, I would like to continue to use my distro's version of matplotlib, which is currently 2.2.4. I've had pretty bad experiences trying to use conda, or other bolt-on python package mangers, on Fedora. Matplotlib installed with conda on Fedora is particularly problematic, maybe because of wayland. I invariably run into library compatibility issues resulting in segfaults, missing symbols, etc...
@ImportanceOfBeingErnest Yes, I believe I was just getting consistently wrong behavior, which I'm ok with to be honest.
As for the other warning, when I run into this problem when I'm making real figures, it only sometimes gives me a warning about tight_layout not being able to process the gridspecs. Often when it does give me a warning, it will still has the desired result of re-sizing subplots to make room for labels and ticks. Maybe I'm just experiencing alarm fatigue, but came to the conclusion that it was safe to ignore.
The probability to find some bug in the cairo backends is currently a little larger than for the agg backends. It seems the cairo backends do not get the same love as the agg backends when it comes to maintainance.
On the other hand the agg backends currently show some really bad issues with marker and tick positionning, which are not present in the cairo case. Having both available is hence a good idea.
As of today, the latest release of matplotlib is 2.2.3. If the bug fix was backported, it would appear in the (yet to be released) version 2.2.4. There will however be a version 3.0 released pretty soonish, which will contain this fix. The main difference is that 2.x is python2 compatible, while 3.x is python3 only. In order to get the fix you will need to use a new version anyways; whether that'll be 2.2.4 or 3.0 or the current development version from github will depend on your other requirements.
I tried to auto-backport #11724, but is says there is a conflict. If someone wants to take up the backport I don't see any problem w/ that, but I don't have the bandwidth...
Activity
jklymak commented on Sep 16, 2018
I don't think your code above is correct. You aren't adding gs_left.
Regardless, I can't reproduce. I get the Actual Outcome with or without the call to tight layout, both on master and v2.2.3.
The only way I get your "Expected" is to set origin='lower'.
galenlynch commented on Sep 16, 2018
Thanks for taking a look. The above code reflects when I see this behavior: I add the image to the right gridspec, and call tight_layout on the left. The output images above are from running the script above from my machine, though you are right I forgot to include the line that makes the empty axis in gs_left. When i have the chance I'll also try it on conda python.
galenlynch commented on Sep 16, 2018
Here is the script that I used to generate the figures above, with the call to gs_left.
@jklymak I do agree that from the documentation, I should need origin='lower' but I have found that at least with interactive mode, I have to use origin = 'upper' to get my desired result.
jklymak commented on Sep 16, 2018
The above does not show the error. What backend are you using (print(matplotlib.get_backend())? I assume you are calling plt.show or running from ipython, or?
ImportanceOfBeingErnest commented on Sep 16, 2018
There is a relatively new tutorial about imshow's origin and extent available here. This shows that what is called "actual outcome" above, is indeed expected for extent = (0, 10, 0, 10), origin = 'upper'.
So if anything is wrong, then it would the "expected outcome". And indeed using the cairo backend ("TkCairo" in my case, since I don't have GTK available), the image is inverted.
What then happens seems that if you use tight_layout, cairo backend will for some reason fall back to agg and the expected outcome with the dark color in the upper left corner is produced, together with a warning UserWarning: tight_layout : falling back to Agg renderer.
So in total there are two potential issues:
ImportanceOfBeingErnest commented on Sep 16, 2018
The "cairo flipping images" issue is been reported in #8798 and fixed in #11724. But it has not been backported to 2.2.x.
galenlynch commented on Sep 16, 2018
My backend is GTK3Cairo. @ImportanceOfBeingErnest is right that I get the agg warning when calling tight from python when interactive mode is off, so given the issues that he mentioned, it seems like cairo images being upside down would explain everything that I've experienced. However, I do not get the agg warning when using interactive mode, and therefore see consistently wrong behavior. To me, the "bug" is mostly that it's inconsistent... I've been pulling my hair out trying to figure out why images in my figures appear one way when plotting them without interactive mode, and are inverted when I use interactive mode. It took my a while to even narrow it down to the tight_layout call.
I've read the tutorial a bunch of times, but it didn't seem to be accurate (didn't know about #8798) so I chalked it up to some version difference or something. I will say that the API for imshow is rather complicated once you start caring about where the image is in an axis.
So it seems like the final verdict is that this is due to #11724 not being backported to my version of matplotlib? Should I close the issue or leave it open as a petition to backport the fix so I don't have to plot twice to get consistently oriented images?
galenlynch commented on Sep 16, 2018
Oh and @jklymak I was looking at the generated file. I get different behavior when I use interactive mode (which I guess is the equivalent of plt.show()?).
jklymak commented on Sep 16, 2018
This is still confusing. Running the code above as a script should not use gtk3cairo. And the bug in #8798 shouldn’t have anything to do w tight_layout. I’d also have thought that saving interactively should still have run through agg but maybe by that point the image is already incorrect. Anyhow the problem has been fixed in master. I don’t see any reason it couldn’t be back ported to 2.2.4.
ImportanceOfBeingErnest commented on Sep 16, 2018
I suppose the user's backend rcParam is simply set to gtk3cairo?!
And then, it's a combination of both, I guess. Without the tight_layout you would probably consistently get the wrong behaviour. So appart from the flipping issue, there is also the question why tight_layout would switch the renderer and whether this is expected.
(There is also another warning about tight_layout not being able to process the gridspecs, so I'm not even sure if it would be extected to work in this case.)
galenlynch commented on Sep 16, 2018
@jklymak If I just start a vanilla python shell and look at the backend, it's already gtk3cairo. Poking around, I realized that I had set it to that (and forgot about it) in my matplotlibrc file. Is there a reason to not use that backend? I did mention it as my backend in the original bug report. I just removed the matplotlibrc.
I would definitely appreciate the bug fix being ported! If at all possible, I would like to continue to use my distro's version of matplotlib, which is currently 2.2.4. I've had pretty bad experiences trying to use conda, or other bolt-on python package mangers, on Fedora. Matplotlib installed with conda on Fedora is particularly problematic, maybe because of wayland. I invariably run into library compatibility issues resulting in segfaults, missing symbols, etc...
@ImportanceOfBeingErnest Yes, I believe I was just getting consistently wrong behavior, which I'm ok with to be honest.
As for the other warning, when I run into this problem when I'm making real figures, it only sometimes gives me a warning about tight_layout not being able to process the gridspecs. Often when it does give me a warning, it will still has the desired result of re-sizing subplots to make room for labels and ticks. Maybe I'm just experiencing alarm fatigue, but came to the conclusion that it was safe to ignore.
ImportanceOfBeingErnest commented on Sep 16, 2018
The probability to find some bug in the cairo backends is currently a little larger than for the agg backends. It seems the cairo backends do not get the same love as the agg backends when it comes to maintainance.
On the other hand the agg backends currently show some really bad issues with marker and tick positionning, which are not present in the cairo case. Having both available is hence a good idea.
As of today, the latest release of matplotlib is 2.2.3. If the bug fix was backported, it would appear in the (yet to be released) version 2.2.4. There will however be a version 3.0 released pretty soonish, which will contain this fix. The main difference is that 2.x is python2 compatible, while 3.x is python3 only. In order to get the fix you will need to use a new version anyways; whether that'll be 2.2.4 or 3.0 or the current development version from github will depend on your other requirements.
galenlynch commented on Sep 17, 2018
Whoops, I meant 2.2.3 -- that's the version that I'm using.
Ok I'll keep in mind that I should try different backends when I run into issues down the road.
Thanks again for both of your help!
jklymak commented on Sep 27, 2018
I tried to auto-backport #11724, but is says there is a conflict. If someone wants to take up the backport I don't see any problem w/ that, but I don't have the bandwidth...
jklymak commented on Sep 27, 2018
Note that 3.0 is released and should fix this bug, so I'll close..