question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Improve multi-axes layout options

See original GitHub issue

Here are some notes on a plan for improving the layout options in the classes defined in seaborn.axisgrid. These objects try to produce plots with “nice layouts” by default, including by placing a joint legend “outside” and then resizing the figure to include it. They also use a different approach to specifying figure size such that the user gives the height and aspect ratio of each facet rather than the total figure size.

Some issues are that

  • The height/aspect parameters are only approximate: the figure size is (n_col * height * aspect, n_row * height) which doesn’t account for the axes/tick labels. Things can really get distorted with long y axes labels, i.e. with horiztonally oriented categorical plots. (I feel like I’ve seen particularly pathological cases where long y axes labels stole space only from the first axes, but am having trouble reproducing, so perhaps matplotlib improved the tight_layout algorithm to handle this better.
  • It’s not possible to specify the legend position.
  • ~Once the legend exist, calling tight_layout again ignores it and stretches the subplots out to overlap with it. This is because in general matplotlib layout algorithms ignore figure-level legends.~ Fixed (in seaborn) by https://github.com/mwaskom/seaborn/pull/2073.
  • ~There are some bad interactions with the macOS backend (#1527)~ (Fixed by https://github.com/matplotlib/matplotlib/issues/15131)

Matplotlib has a new constrained layout manager which could give better performance than the current approach of periodically calling tight_layout. It is currently described as “experimental” so it can’t be the default but it could be made an option.

I’d also like to replace the bespoke approach to modifying the figure size to account for the legend by using the existing bbox_inches="tight" machinery, and also extend it to expand the figure to include the axis ticks and labels in a way that doesn’t distort the requested size and aspect ratio.

I’ve figured out some of this. Here’s a relevant example:

f, ax = plt.subplots(figsize=(4, 4))

f.subplots_adjust(0, 0, 1, 1)
ax.plot([0, 1], [0, 1], label="the plot")
ax.legend(loc="center left", bbox_to_anchor=(1, .5))

renderer = f.canvas.get_renderer()
f.draw(renderer)
bbox = f.get_tightbbox(renderer)
tight_bbox.adjust_bbox(f, bbox.padded(.05))

image

The basic approach then is going to be to set up the subplot array, set the subplot params to minimize exterior padding, delegate arrangement of the interior of the plot to tight_layout or constrained_layout, and then use an “expand figure” operation with the above logic when the legend/labels change.

Other related ideas:

  • Adding single labels for x and y variables. This is actually a little tricky to do in a way that will get updated properly by {tight,constrained}_layout. Maybe worth pitching “subplot labels” to matplotlib, although we couldn’t use them yet.
  • Set the default size by some kind of scaling factor from the rcParams default figure size? This is a point of confusion for people but there’s not an obvious way to do it.
  • Using relplot, catplot, and lmplot without specifying col or row returns a FacetGrid which is maybe confusing? Perhaps this could be slightly different class that shares relevant methods.
  • No way to add a shared continuous colorbar, which has been requested a bunch.
  • Maybe add a parameter like adjust_strategy which can be "expand" or "contract", where "expand" uses the approach described above and "contract" keeps the plot at the original size.
  • Add a FacetGrid.set_prop (or similiar — matplotlib uses setp which is not very discoverable) with the api set_prop(artists, **kwargs) which iterates through the axes, gets the relevant artist, and sets properties on them.
  • Need better documentation for how figure size is determined and what to do if you really want an exact total figure size.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
mwaskomcommented, May 7, 2020

Yep, that’s the basic idea. The tricky part is going to be combining that with either constrained_layout or tight_layout to get nice automatic spacing on the interior of a subplot grid without changing the aspect ratio.

I guess, formally, I want the automatic transformations to translate the axes but not scale them.

0reactions
jklymakcommented, May 7, 2020

I see, so you want the equivalent of bbox_inches='tight' but at draw time instead of save time? i.e. 6, 3 is the “natural” size, but it will expand if that is too small?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Arranging multiple Axes in a Figure - Matplotlib
However, they present a challenge to layout because two sets of constraints are being imposed on the size of the Axes - that...
Read more >
Change the display of chart axes - Microsoft Support
You can change the alignment of axis labels on both horizontal (category) and vertical (value) axes. When you have multiple-level category labels in...
Read more >
Control Axes Layout - MATLAB & Simulink - MathWorks
Control the axes size and position, the layout of titles and labels, and the axes resize behavior.
Read more >
Add Axes for Multiple Measures in Views - Tableau Help
The Synchronize Axis option ensures that you make a scaled and correct comparison in a dual axes chart. However, sometimes this option may...
Read more >
Managing Axes in OVERLAY Layouts - SAS Help Center
Layout statements provide many axis options that change the default axis ... entrytitle "Y and Y2 Axes Use Different Data"; layout overlay ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found