8000 tight_layout: Use a different default gridspec by tomspur · Pull Request #4559 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

tight_layout: Use a different default gridspec #4559

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

Closed
wants to merge 4 commits into from

Conversation

tomspur
Copy link
Contributor
@tomspur tomspur commented Jun 26, 2015

This commit adds a default _subplotspec to all axes, which will help with
building a better image when using tight_layout. At least in my testcase, the
images with and without tight_layout are close to identical after this commit
and it does look really odd without this default _subplotspec.

I doubt, this is the right thing to do. But if it works on a broader case of figures, we'll see if it is not a bad idea or not.

My testcase is a modified version of the griddata_demo.py. If this should be added to the tests let me know:

from numpy.random import uniform, seed
from matplotlib.mlab import griddata
import matplotlib.pyplot as plt
import numpy as np
# make up data.
#npts = int(raw_input('enter # of random points to plot:'))
seed(0)
npts = 200
x = uniform(-2, 2, npts)
y = uniform(-2, 2, npts)
z = x*np.exp(-x**2 - y**2)
# define grid.
xi = np.linspace(-2.1, 2.1, 100)
yi = np.linspace(-2.1, 2.1, 200)
# grid the data.
zi = griddata(x, y, z, xi, yi, interp='linear')


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

fig.set_tight_layout(True)

# contour the gridded data, plotting dots at the nonuniform data points.
CS = plt.contour(xi, yi, zi, 15, linewidths=0.5, colors='k')
CS = axes[1].contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
                  vmax=abs(zi).max(), vmin=-abs(zi).max())
CS = axes[0].contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
                  vmax=abs(zi).max(), vmin=-abs(zi).max())
#plt.colorbar()  # draw colorbar
# draw colorbar at the right:

# plot data points.
plt.scatter(x, y, marker='o', c='b', s=5, zorder=10)
plt.xlim(-2, 2)
plt.ylim(-2, 2)
#plt.title('griddata test (%d points)' % npts)

fig.subplots_adjust(right=0.8)
cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])
cbar = fig.colorbar(CS, cax=cbar_ax)

plt.savefig("test.pdf") #show()

@tomspur
Copy link
Contributor Author
tomspur commented Jun 26, 2015

The python2.6 failure seems unrelated...

@WeatherGod
Copy link
Member

I think you need to be a little bit more descriptive about what you mean by letting tight_layout do the right thing.

@tacaswell
Copy link
Member

I kicked the test to restart.

A less intrusive patch would be to change the default value from None -> gridspec.GridSpec(1, 1)?

Does this still do the right thing the user creates multiple figures using a method which does not otherwise add _subplotspec will result in multiple axes all thinking they are the only axes?

I am not super familiar with this section of the code base, but my knee-jerk reaction is that this patch will have nasty side effects (that we apparently don't test?).

@tomspur
Copy link
Contributor Author
tomspur commented Jun 26, 2015

Here is the resulting image without the patch:
test_true_without_patch

and this is after the patch (which is basically looking the same as not using tight_layout):
test_true

So it seems this patch corrects the picture to match the result of not using tight_layout (which I meant above with "doing the right thing").

@tacaswell: I'm unsure, if there are other cases, where get_subplotspec_list could be called on, so I added it to the _AxesBase, so also Axes would have it inherited.
I don't understand the second question...

I also expected side effects and wanted to post this to see some failing tests...

@tacaswell tacaswell added this to the proposed next point release milestone Jun 26, 2015
@WeatherGod
Copy link
Member

A picture is worth a million words. I now see what you are talking about.

What I think is happening is that the location of the colorbar axes is being defined by fractions of the figure space outside of the subplot spec system. Tight layout adjusts the spacing of items defined by the subplot spec system. So, it is completely unaware of other axes elements that were added to the figure in other ways.

So, I think the important question here is whether or not this is really a bug in the first place? tight_layout is doing exactly what it is supposed to be doing -- finding an optimal layout for axes in the subplot grid spec. It just so happens that the user has other axes in the figure that are custom placed.

I would argue that this actually introduces a bug, because now the colorbar is no longer placed where I told it to be. Indeed, I do know of people who like to put their colorbars in custom locations, oftentimes inside a plot area, and would be pissed to no end if tight_layout all the sudden changed this.

Perhaps we need to improve the colorbar api to allow for different intentions?

@tomspur
Copy link
Contributor Author
tomspur commented Jun 26, 2015

If I understand your "bug" correctly, the colorbar inside the plot area should look like this:
test_true_with_patch_without_adjust

This picture was created with the patch and tight_layout. All I did is I uncommented the line fig.subplots_adjust(right=0.8) from the script above.
So if you don't adjust the subplots you should obtain the colorbar at your location without moving the underlying plot away, isn't it?

For comparison, the picture without colorbar looks like this:
test_true_with_patch_without_adjust_no_cbar

So it is indeed a bit moved/smaller than with the colorbar, but I'd say it's possible to put the colorbar inside the main picture or I didn't understand your bug...

@WeatherGod
Copy link
Member

indeed... I guess I am not fully understanding what is going on here, then.

@efiring
Copy link
Member
efiring commented Jun 26, 2015

This doesn't involve the colorbar API; the Figure.add_axes() method is making the colorbar Axes.
Colorbar already has a 'use_gridspec' option which is active when it is making its own axes by stealing space from another axes.
I suspect the real solution here might involve using a gridspec-based method of making the axes for the colorbar, instead of Figure.add_axes().

@tomspur tomspur force-pushed the axes_tight_layout branch from 02fbbe3 to 9195a88 Compare July 3, 2015 17:57
@tomspur tomspur changed the title Add a default _subplotspec to all axes tight_layout: Use a different default gridspec Jul 3, 2015
@tomspur
Copy link
Contributor Author
tomspur commented Jul 3, 2015

The example above was based on this example and I think that one should be(come) supported also with tight_layout.

The updated patch looks now much nicer and tight_layout now just uses another default value when a figure does not implement the gridspec yet. Furthermore, it cleans the code a bit as all is contained in tight_layout.py and the same warning as before is retained.

The last commit adds a test for the case of one picture and a colorbar. That one is identical to the output before, but makes sure to not break it in the future. My testcase for two figures unfortunately cuts off the labels a bit, so that one is not yet fully finished for regtesting and I like to leave that for a future improvement...

@tacaswell
Copy link
Member

Just a ping to remind you we are alive and have not forgotten you.

@tomspur tomspur force-pushed the axes_tight_layout branch from b6eb13f to 1717f37 Compare October 5, 2015 21:16
@tacaswell tacaswell closed this Dec 14, 2015
@tacaswell tacaswell reopened this Dec 14, 2015
@tacaswell tacaswell modified the milestones: next major release (2.0), proposed next point release (2.1) Dec 14, 2015
@tomspur
Copy link
Contributor Author
tomspur commented Dec 14, 2015

I am quite sure that the checks were completing. Will try to look into the failure soonish.

@tacaswell
Copy link
Member

It is probably the text. Sense you did this we a) now have a way to install a specific version of freetype for testing and b) have zero-tolerance testing on the image comparisons.

@tomspur tomspur force-pushed the axes_tight_layout branch 4 times, most recent 8000 ly from c9bb7a8 to 0af60d4 Compare December 15, 2015 12:26
@tomspur
Copy link
Contributor Author
tomspur commented Dec 15, 2015

Should be fine now. It took me a while to notice that python setup.py test is not the same as running tests.py, maybe the former could call the latter, so that it is more obvious that not the right freetype fonts were used?

@jenshnielsen
Copy link
Member

setup.py test is hoefully going away see #5434

@tomspur
Copy link
Contributor Author
tomspur commented Dec 15, 2015

Great, thanks

@tomspur
Copy link
Contributor Author
tomspur commented Dec 17, 2015

The appveyor HTTPError: 404 Client Error failure seems unrelated.

@jankatins
Copy link
Contributor

re appveyor: I agree :-)

Error: HTTPError: 404 Client Error: Not Found for url: https://conda.anaconda.org/conda-forge/win-64/msinttypes-r26-0.tar.bz2: https://conda.anaconda.org/conda-forge/win-64/msinttypes-r26-0.tar.bz2

-> conda can't find its packages...

@tomspur tomspur force-pushed the axes_tight_layout branch 2 times, most recently from aa2acd6 to 1a3f54f Compare January 5, 2016 20:34
@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.0 (style change major release) Jan 25, 2016
@efiring
Copy link
Member
efiring commented Jan 25, 2016

Note: instead of removing the warnings, they could be made more informative as to how make the Axes compatible with tight_layout.

@tomspur tomspur force-pushed the axes_tight_layout branch from 1a3f54f to 6c29ccc Compare May 8, 2016 00:24
@tomspur
Copy link
Contributor Author
tomspur commented May 9, 2016

After rebasing, the new tests added above don't pass anymore.
I'll look into this.

I didn't remove the warnings, I just refactored them to another place. But I'll also look into making them more informative, while at it.

@tomspur tomspur force-pushed the axes_tight_layout branch 2 times, most recently from 91d7ff0 to a0c2b33 Compare December 5, 2016 22:09
@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Sep 24, 2017
tomspur added 3 commits April 3, 2018 01:03
This commit adds a default gridspec to tight_layout. It helps to build a better
wimage when using tight_layout with figures that do not (yet) implement their
own gridspec. This does not affect figures that do not use tight_layout and
only improves the case with tight_layout at least in my testcases.

The warning, that warns from the usage of figures that have no gridspec
implemented is retained.
67E6
@tomspur tomspur force-pushed the axes_tight_layout branch from b1642d5 to a6f88c8 Compare April 2, 2018 23:05
@tomspur tomspur force-pushed the axes_tight_layout branch from 6601685 to 8770e82 Compare April 2, 2018 23:42
@jklymak
Copy link
Member
jklymak commented Apr 3, 2018

I'm not quite sure why this PR works, or if it does for anything other than the test. If the gridspecs don't know about each other, I'm not sure how they negotiate which should be placed where.

If we changed the gridspec hierarchy so that the gridspecs knew about the figure that contains them, then we could make this all work but thats not how GridSpec currently works by default.

For fun, you could try constrained_layout, which was meant for exactly this problem.

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

CS = plt.contour(xi, yi, zi, 15, linewidths=0.5, colors='k')
CS = axes[1].contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
                  vmax=abs(zi).max(), vmin=-abs(zi).max())
CS = axes[0].contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
                  vmax=abs(zi).max(), vmin=-abs(zi).max())
cbar = fig.colorbar(CS, ax=axes, shrink=0.8)
plt.show()

@jklymak jklymak modified the milestones: needs sorting, v3.0 Apr 3, 2018
@tomspur
Copy link
Contributor Author
tomspur commented Apr 3, 2018

With constrained_layout it looks better as the original code from above at least. Left is the constrained_layout version and on the right the original code from above with this branch:
bildschirmfoto vom 2018-04-03 12-59-30

You know for sure more about the gridspec machinery than I do. If I read the gridspec docs correctly, the gridspec of (1, 1) does add a single subgrid to every new item, which it did not have any grid specs for, which seems to at least work for the case from above.

@jklymak
Copy link
Member
jklymak commented May 6, 2018

I'm going to close this - this just allows tight_layout to be called, but tight_layout doesn't do anything, so its better to error rather than mislead the user that something is happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants
0