Skip to content

[ENH]: Allow ignoring x-extent (but not y-extent) of xticklabels when computing axes extents (e.g. for geometry manager) #30263

Open
@anntzer

Description

@anntzer

Problem

Currently, if an xtick is at the very edge of an x-axis, and thus the xticklabel "overhangs" further, then it will be taken into account for constrained_layout (CL) purposes. Unfortunately, this means that the axes size, after CL runs, will depend on whether there is such an "edge" xtick. In some cases, it may be preferable to ignore the x-extent of that ticklabel, even if it ends up "going over" the edge of the figure, to maintain the same axes size. (An example use case is when exporting multiple figures, all with similar axes only differing by whether there's an overhanging xticklabel, to SVG, as with this format one can just readjust the viewport of the SVG to unclip the ticklabel.)

Concretely, consider the following example:

from pylab import *

ax = plt.figure(layout="constrained", figsize=(3, 3)).add_subplot(xlim=(-.1, 1.1))
ax = plt.figure(layout="constrained", figsize=(3, 3)).add_subplot(xlim=(0, 1))

show()

Right now the axes have slightly different physical sizes, because the second one is reduced to give room to the edge tick at x=1.

I would like to be able to do something like (*)

from pylab import *

ax = plt.figure(layout="constrained", figsize=(3, 3)).add_subplot(xlim=(-.1, 1.1))
ax = plt.figure(layout="constrained", figsize=(3, 3)).add_subplot(xlim=(0, 1))
ax.figure.draw_without_rendering()
ax.xaxis.majorTicks[-1].label1.set_in_layout(False)

show()

to force the last xtick to be ignored for CL purposes.

Making this work is actually relatively easy; I believe the patch is simply

diff --git i/lib/matplotlib/axis.py w/lib/matplotlib/axis.py
index fafdf92017..a9b31ebb4e 100644
--- i/lib/matplotlib/axis.py
+++ w/lib/matplotlib/axis.py
@@ -1335,9 +1335,11 @@ class Axis(martist.Artist):
         if renderer is None:
             renderer = self.get_figure(root=True)._get_renderer()
         return ([tick.label1.get_window_extent(renderer)
-                 for tick in ticks if tick.label1.get_visible()],
+                 for tick in ticks
+                 if tick.label1.get_visible() and tick.label1.get_in_layout()],
                 [tick.label2.get_window_extent(renderer)
-                 for tick in ticks if tick.label2.get_visible()])
+                 for tick in ticks
+                 if tick.label2.get_visible() and tick.label2.get_in_layout()])
 
     def get_tightbbox(self, renderer=None, *, for_layout_only=False):
         """

but a few questions remain

  • The end-user experience is not great if one really needs to do (*); can we design a better API?
  • Ideally, I only want to ignore the x-extent of the xticklabels, not their y-extent (although in practice I'm saved by the fact that other xticks contribute the necessary info for the y-extent). Should we introduce set_in_layout_x() and set_in_layout_y()?

Of course, the same applies for the y-extent of yticklabels.

Proposed solution

See above.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy