Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 86a6e32

Browse filesBrowse files
committed
start at aligning x and y labels
First crack First crack PEP 8 Slight refactor Handles left and right top and bottom labels Add fig.align_labels() wrapper Add fig.align_labels() wrapper Fixed error w xlabels Doc and tests Doc and tests Doc and tests Doc and tests Small Change Documentation fixes. Thanks anntzer Fix axs is a ndarray case PEP8 Try to fix numpydoc Try to fix numpydoc Try to fix numpydoc Try to fix numpydoc Fixed typo
1 parent 0e3dd2d commit 86a6e32
Copy full SHA for 86a6e32

File tree

9 files changed

+3107
-10
lines changed
Filter options

9 files changed

+3107
-10
lines changed
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
xlabels and ylabels can now be automatically aligned
2+
----------------------------------------------------
3+
4+
Subplot axes ``ylabels`` can be misaligned horizontally if the tick labels
5+
are very different widths. The same can happen to ``xlabels`` if the
6+
ticklabels are rotated on one subplot (for instance). The new methods
7+
on the `Figure` class: `Figure.align_xlabels` and `Figure.align_ylabels`
8+
will now align these labels horizontally or vertically. If the user only
9+
wants to align some axes, a list of axes can be passed. If no list is
10+
passed, the algorithm looks at all the labels on the figure.
11+
12+
Only labels that have the same subplot locations are aligned. i.e. the
13+
ylabels are aligned only if the subplots are in the same column of the
14+
subplot layout.
15+
16+
A convenience wrapper `Figure.align_labels` calls both functions at once.
17+
18+
.. plot::
19+
20+
import matplotlib.gridspec as gridspec
21+
22+
fig = plt.figure(figsize=(5, 3), tight_layout=True)
23+
gs = gridspec.GridSpec(2, 2)
24+
25+
ax = fig.add_subplot(gs[0,:])
26+
ax.plot(np.arange(0, 1e6, 1000))
27+
ax.set_ylabel('Test')
28+
for i in range(2):
29+
ax = fig.add_subplot(gs[1, i])
30+
ax.set_ylabel('Booooo')
31+
ax.set_xlabel('Hello')
32+
if i == 0:
33+
for tick in ax.get_xticklabels():
34+
tick.set_rotation(45)
35+
fig.align_labels()
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
"""
2+
===============
3+
Aligning Labels
4+
===============
5+
6+
Aligning xlabel and ylabel using
7+
`Figure.align_xlabels` and
8+
`Figure.align_ylabels`
9+
10+
`Figure.align_labels` wraps these two functions.
11+
12+
Note that
13+
the xlabel "XLabel1 1" would normally be much closer to the x-axis, and
14+
"YLabel1 0" would be much closer to the y-axis of their respective axes.
15+
"""
16+
import matplotlib.pyplot as plt
17+
import numpy as np
18+
import matplotlib.gridspec as gridspec
19+
20+
fig = plt.figure(tight_layout=True)
21+
gs = gridspec.GridSpec(2, 2)
22+
23+
ax = fig.add_subplot(gs[0, :])
24+
ax.plot(np.arange(0, 1e6, 1000))
25+
ax.set_ylabel('YLabel0')
26+
ax.set_xlabel('XLabel0')
27+
28+
for i in range(2):
29+
ax = fig.add_subplot(gs[1, i])
30+
ax.plot(np.arange(1., 0., -0.1) * 2000., np.arange(1., 0., -0.1))
31+
ax.set_ylabel('YLabel1 %d' % i)
32+
ax.set_xlabel('XLabel1 %d' % i)
33+
if i == 0:
34+
for tick in ax.get_xticklabels():
35+
tick.set_rotation(55)
36+
fig.align_labels() # same as fig.align_xlabels() and fig.align_ylabels()
37+
38+
plt.show()

‎lib/matplotlib/axis.py

Copy file name to clipboardExpand all lines: lib/matplotlib/axis.py
+37-8Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,7 @@ def __init__(self, axes, pickradius=15):
662662

663663
self._autolabelpos = True
664664
self._smart_bounds = False
665+
self._align_label_siblings = [self]
665666

666667
self.label = self._get_label()
667668
self.labelpad = rcParams['axes.labelpad']
@@ -1089,10 +1090,12 @@ def get_tightbbox(self, renderer):
10891090
return
10901091

10911092
ticks_to_draw = self._update_ticks(renderer)
1092-
ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw,
1093-
renderer)
10941093

1095-
self._update_label_position(ticklabelBoxes, ticklabelBoxes2)
1094+
self._update_label_position(renderer)
1095+
1096+
# go back to just this axis's tick labels
1097+
ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(
1098+
ticks_to_draw, renderer)
10961099

10971100
self._update_offset_text_position(ticklabelBoxes, ticklabelBoxes2)
10981101
self.offsetText.set_text(self.major.formatter.get_offset())
@@ -1143,7 +1146,7 @@ def draw(self, renderer, *args, **kwargs):
11431146
# *copy* of the axis label box because we don't wan't to scale
11441147
# the actual bbox
11451148

1146-
self._update_label_position(ticklabelBoxes, ticklabelBoxes2)
1149+
self._update_label_position(renderer)
11471150

11481151
self.label.draw(renderer)
11491152

@@ -1655,7 +1658,24 @@ def set_ticks(self, ticks, minor=False):
16551658
self.set_major_locator(mticker.FixedLocator(ticks))
16561659
return self.get_major_ticks(len(ticks))
16571660

1658-
def _update_label_position(self, bboxes, bboxes2):
1661+
def _get_tick_boxes_siblings(self, renderer):
1662+
"""
1663+
Get the bounding boxes for this axis and its sibblings
1664+
as set by `Figure.align_xlabels` or ``Figure.align_ylables`.
1665+
1666+
By default it just gets bboxes for self.
1667+
"""
1668+
bboxes = []
1669+
bboxes2 = []
1670+
# if we want to align labels from other axes:
1671+
for axx in self._align_label_siblings:
1672+
ticks_to_draw = axx._update_ticks(renderer)
1673+
tlb, tlb2 = axx._get_tick_bboxes(ticks_to_draw, renderer)
1674+
bboxes.extend(tlb)
1675+
bboxes2.extend(tlb2)
1676+
return bboxes, bboxes2
1677+
1678+
def _update_label_position(self, renderer):
16591679
"""
16601680
Update the label position based on the bounding box enclosing
16611681
all the ticklabels and axis spine
@@ -1832,13 +1852,18 @@ def set_label_position(self, position):
18321852
self.label_position = position
18331853
self.stale = True
18341854

1835-
def _update_label_position(self, bboxes, bboxes2):
1855+
def _update_label_position(self, renderer):
18361856
"""
18371857
Update the label position based on the bounding box enclosing
18381858
all the ticklabels and axis spine
18391859
"""
18401860
if not self._autolabelpos:
18411861
return
1862+
1863+
# get bounding boxes for this axis and any siblings
1864+
# that have been set by `fig.align_xlabels()`
1865+
bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer)
1866+
18421867
x, y = self.label.get_position()
18431868
if self.label_position == 'bottom':
18441869
try:
@@ -2160,13 +2185,18 @@ def set_label_position(self, position):
21602185
self.label_position = position
21612186
self.stale = True
21622187

2163-
def _update_label_position(self, bboxes, bboxes2):
2188+
def _update_label_position(self, renderer):
21642189
"""
21652190
Update the label position based on the bounding box enclosing
21662191
all the ticklabels and axis spine
21672192
"""
21682193
if not self._autolabelpos:
21692194
return
2195+
2196+
# get bounding boxes for this axis and any siblings
2197+
# that have been set by `fig.align_ylabels()`
2198+
bboxes, bboxes2 = self._get_tick_boxes_siblings(renderer)
2199+
21702200
x, y = self.label.get_position()
21712201
if self.label_position == 'left':
21722202
try:
@@ -2178,7 +2208,6 @@ def _update_label_position(self, bboxes, bboxes2):
21782208
spinebbox = self.axes.bbox
21792209
bbox = mtransforms.Bbox.union(bboxes + [spinebbox])
21802210
left = bbox.x0
2181-
21822211
self.label.set_position(
21832212
(left - self.labelpad * self.figure.dpi / 72.0, y)
21842213
)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.