Skip to content

Commit 53f547f

Browse files
committed
More concicse how to for subplot adjustment.
- Repurpose the example "Auto Subplots Adjust" to "Programmatically controlling subplot adjustment". The effect of the example has been largely superseeded by tight layout and constrained layout. It's still useful as an example of using advanced concepts in Matplotlib such as Bboxes, transforms, events. - Remove "How-to: Move the edge of an axes to make room for tick labels" and move it's content to "Programmatically controlling subplot adjustment" - Remove "How-to: Automatically make room for tick labels" This is basically a documentation of `subplots_adjust()`. It's sufficient to link there. - Write a single new section "How to: "Make room for tick labels" that only links to manual adjustment / tight layout / constrained layout / "Programmatically controlling subplot adjustment"
1 parent 831a13c commit 53f547f

File tree

4 files changed

+62
-116
lines changed

4 files changed

+62
-116
lines changed

doc/faq/howto_faq.rst

Lines changed: 13 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -137,106 +137,25 @@ The same can be done using the pgf backend::
137137

138138
from matplotlib.backends.backend_pgf import PdfPages
139139

140-
.. _howto-subplots-adjust:
141140

142-
Move the edge of an axes to make room for tick labels
143-
-----------------------------------------------------
144-
145-
For subplots, you can control the default spacing on the left, right,
146-
bottom, and top as well as the horizontal and vertical spacing between
147-
multiple rows and columns using the
148-
:meth:`matplotlib.figure.Figure.subplots_adjust` method (in pyplot it
149-
is :func:`~matplotlib.pyplot.subplots_adjust`). For example, to move
150-
the bottom of the subplots up to make room for some rotated x tick
151-
labels::
141+
.. _howto-auto-adjust:
152142

153-
fig = plt.figure()
154-
fig.subplots_adjust(bottom=0.2)
155-
ax = fig.add_subplot(111)
143+
Make room for tick labels
144+
-------------------------
156145

157-
You can control the defaults for these parameters in your
158-
:file:`matplotlibrc` file; see :doc:`/tutorials/introductory/customizing`. For
159-
example, to make the above setting permanent, you would set::
160-
161-
figure.subplot.bottom : 0.2 # the bottom of the subplots of the figure
162-
163-
The other parameters you can configure are, with their defaults
164-
165-
*left* = 0.125
166-
the left side of the subplots of the figure
167-
*right* = 0.9
168-
the right side of the subplots of the figure
169-
*bottom* = 0.1
170-
the bottom of the subplots of the figure
171-
*top* = 0.9
172-
the top of the subplots of the figure
173-
*wspace* = 0.2
174-
the amount of width reserved for space between subplots,
175-
expressed as a fraction of the average axis width
176-
*hspace* = 0.2
177-
the amount of height reserved for space between subplots,
178-
expressed as a fraction of the average axis height
179-
180-
If you want additional control, you can create an
181-
:class:`~matplotlib.axes.Axes` using the
182-
:func:`~matplotlib.pyplot.axes` command (or equivalently the figure
183-
:meth:`~matplotlib.figure.Figure.add_axes` method), which allows you to
184-
specify the location explicitly::
185-
186-
ax = fig.add_axes([left, bottom, width, height])
187-
188-
where all values are in fractional (0 to 1) coordinates. See
189-
:doc:`/gallery/subplots_axes_and_figures/axes_demo` for an example of
190-
placing axes manually.
146+
By default, Matplotlib uses fixed percentage margins around subplots. This can
147+
lead to labels overlapping or being cut off at the figure boundary. There are
148+
multiple ways to fix this:
191149

192-
.. _howto-auto-adjust:
150+
- Manually adapt the subplot parameters using `.Figure.subplots_adjust` /
151+
`.pyplot.subplots_adjust`.
152+
- Use one of the automatic layout mechanisms:
193153

194-
Automatically make room for tick labels
195-
---------------------------------------
154+
- constrained layout (:doc:`/tutorials/intermediate/constrainedlayout_guide`)
155+
- tight layout (:doc:`/tutorials/intermediate/tight_layout_guide`)
196156

197-
.. note::
198-
This is now easier to handle than ever before.
199-
Calling :func:`~matplotlib.pyplot.tight_layout` or alternatively using
200-
``constrained_layout=True`` argument in :func:`~matplotlib.pyplot.subplots`
201-
can fix many common layout issues. See the
202-
:doc:`/tutorials/intermediate/tight_layout_guide` and
203-
:doc:`/tutorials/intermediate/constrainedlayout_guide` for more details.
204-
205-
The information below is kept here in case it is useful for other
206-
purposes.
207-
208-
In most use cases, it is enough to simply change the subplots adjust
209-
parameters as described in :ref:`howto-subplots-adjust`. But in some
210-
cases, you don't know ahead of time what your tick labels will be, or
211-
how large they will be (data and labels outside your control may be
212-
being fed into your graphing application), and you may need to
213-
automatically adjust your subplot parameters based on the size of the
214-
tick labels. Any :class:`~matplotlib.text.Text` instance can report
215-
its extent in window coordinates (a negative x coordinate is outside
216-
the window), but there is a rub.
217-
218-
The :class:`~matplotlib.backend_bases.RendererBase` instance, which is
219-
used to calculate the text size, is not known until the figure is
220-
drawn (:meth:`~matplotlib.figure.Figure.draw`). After the window is
221-
drawn and the text instance knows its renderer, you can call
222-
:meth:`~matplotlib.text.Text.get_window_extent`. One way to solve
223-
this chicken and egg problem is to wait until the figure is draw by
224-
connecting
225-
(:meth:`~matplotlib.backend_bases.FigureCanvasBase.mpl_connect`) to the
226-
"on_draw" signal (:class:`~matplotlib.backend_bases.DrawEvent`) and
227-
get the window extent there, and then do something with it, e.g., move
228-
the left of the canvas over; see :ref:`event-handling-tutorial`.
229-
230-
Here is an example that gets a bounding box in relative figure coordinates
231-
(0..1) of each of the labels and uses it to move the left of the subplots
232-
over so that the tick labels fit in the figure:
233-
234-
.. figure:: ../gallery/pyplots/images/sphx_glr_auto_subplots_adjust_001.png
235-
:target: ../gallery/pyplots/auto_subplots_adjust.html
236-
:align: center
237-
:scale: 50
238-
239-
Auto Subplots Adjust
157+
- Calculate good values from the size of the plot elements yourself
158+
(:doc:`/gallery/pyplots/auto_subplots_adjust`)
240159

241160
.. _howto-align-label:
242161

examples/pyplots/auto_subplots_adjust.py

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
11
"""
2-
====================
3-
Auto Subplots Adjust
4-
====================
2+
===============================================
3+
Programmatically controlling subplot adjustment
4+
===============================================
55
6-
Automatically adjust subplot parameters. This example shows a way to determine
7-
a subplot parameter from the extent of the ticklabels using a callback on the
8-
:doc:`draw_event</users/event_handling>`.
6+
.. note::
97
10-
Note that a similar result would be achieved using `~.Figure.tight_layout`
11-
or `~.Figure.set_constrained_layout`; this example shows how one could
12-
customize the subplot parameter adjustment.
8+
This example is primarily intended to show some advanced concepts in
9+
Matplotlib.
10+
11+
If you are only looking for having enough space for your labels, it is
12+
almost always simpler and good enough to either set the subplot parameters
13+
manually using `.Figure.subplots_adjust`, or use one of the automatic
14+
layout mechanisms
15+
(:doc:`/tutorials/intermediate/constrainedlayout_guide` or
16+
:doc:`/tutorials/intermediate/tight_layout_guide`).
17+
18+
This example describes a user-defined way to read out Artist sizes and
19+
set the subplot parameters accordingly. Its main purpose is to illustrate
20+
some advanced concepts like reading out text positions, working with
21+
bounding boxes and transforms and using
22+
:ref:`events <event-handling-tutorial>`. But it can also serve as a starting
23+
point if you want to automate the layouting and need more flexibility than
24+
tight layout and constrained layout.
25+
26+
Below, we collect the bounding boxes of all y-labels and move the left border
27+
of the subplot to the right so that it leaves enough room for the union of all
28+
the bounding boxes.
29+
30+
There's one catch with calculating text bounding boxes:
31+
Querying the text bounding boxes (`.Text.get_window_extent`) needs a
32+
renderer (`.RendererBase` instance), to calculate the text size. This renderer
33+
is only available after the figure has been drawn (`.Figure.draw`).
34+
35+
A solution to this is putting the adjustment logic in a draw callback.
36+
This function is executed after the figure has been drawn. It can now check
37+
if the subplot leaves enough room for the text. If not, the subplot parameters
38+
are updated and second draw is triggered.
1339
"""
1440

1541
import matplotlib.pyplot as plt
@@ -24,15 +50,16 @@
2450
def on_draw(event):
2551
bboxes = []
2652
for label in labels:
27-
bbox = label.get_window_extent()
28-
# the figure transform goes from relative coords->pixels and we
29-
# want the inverse of that
30-
bboxi = bbox.transformed(fig.transFigure.inverted())
31-
bboxes.append(bboxi)
53+
# Bounding box in pixels
54+
bbox_px = label.get_window_extent()
55+
# Transform to relative figure coordinates. This is the inverse of
56+
# transFigure.
57+
bbox_fig = bbox_px.transformed(fig.transFigure.inverted())
58+
bboxes.append(bbox_fig)
3259
# the bbox that bounds all the bboxes, again in relative figure coords
3360
bbox = mtransforms.Bbox.union(bboxes)
3461
if fig.subplotpars.left < bbox.width:
35-
# we need to move it over
62+
# Move the subplot left edge more to the right
3663
fig.subplots_adjust(left=1.1*bbox.width) # pad a little
3764
fig.canvas.draw()
3865

tutorials/intermediate/constrainedlayout_guide.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ def example_plot(ax, fontsize=12, hide_labels=False):
7777

7878
###############################################################################
7979
# To prevent this, the location of axes needs to be adjusted. For
80-
# subplots, this can be done by adjusting the subplot params
81-
# (:ref:`howto-subplots-adjust`). However, specifying your figure with the
82-
# ``constrained_layout=True`` keyword argument will do the adjusting
83-
# automatically.
80+
# subplots, this can be done manually by adjusting the subplot parameters
81+
# using `.Figure.subplots_adjust`. However, specifying your figure with the
82+
# # ``constrained_layout=True`` keyword argument will do the adjusting
83+
# # automatically.
8484

8585
fig, ax = plt.subplots(constrained_layout=True)
8686
example_plot(ax, fontsize=24)

tutorials/intermediate/tight_layout_guide.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ def example_plot(ax, fontsize=12):
4646

4747
###############################################################################
4848
# To prevent this, the location of axes needs to be adjusted. For
49-
# subplots, this can be done by adjusting the subplot params
50-
# (:ref:`howto-subplots-adjust`). Matplotlib v1.1 introduced
51-
# `.Figure.tight_layout` that does this automatically for you.
49+
# subplots, this can be done manually by adjusting the subplot parameters
50+
# using `.Figure.subplots_adjust`. `.Figure.tight_layout` does this
51+
# automatically.
5252

5353
fig, ax = plt.subplots()
5454
example_plot(ax, fontsize=24)

0 commit comments

Comments
 (0)