Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/users/next_whats_new/legend_align.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Legend can control alignment of title and handles
-------------------------------------------------

`.Legend` now supports control the alignment of title and handles via the
keyword argument ``alignment``. You can also use `.Legend.set_alignment`
to control the alignment on existing Legends.
45 changes: 42 additions & 3 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ def _update_bbox_to_anchor(self, loc_in_canvas):
to set the fontsize alongside other font properties, use the *size*
parameter in *title_fontproperties*.

alignment : {'center', 'left', 'right'}, default: 'center'
The alignment of the legend title and the box of entries. The entries
are aligned as a single block, so that markers always lined up.

borderpad : float, default: :rc:`legend.borderpad`
The fractional whitespace inside the legend border, in font-size units.

Expand Down Expand Up @@ -336,6 +340,7 @@ def __init__(
frameon=None, # draw frame
handler_map=None,
title_fontproperties=None, # properties for the legend title
alignment="center", # control the alignment within the legend box
*,
ncol=1 # synonym for ncols (backward compatibility)
):
Expand Down Expand Up @@ -505,6 +510,9 @@ def val_or_rc(val, rc_name):
)
self._set_artist_props(self.legendPatch)

_api.check_in_list(["center", "left", "right"], alignment=alignment)
self._alignment = alignment

# init with null renderer
self._init_legend_box(handles, labels, markerfirst)

Expand Down Expand Up @@ -804,7 +812,7 @@ def _init_legend_box(self, handles, labels, markerfirst=True):
self._legend_title_box = TextArea("")
self._legend_box = VPacker(pad=self.borderpad * fontsize,
sep=self.labelspacing * fontsize,
align="center",
align=self._alignment,
children=[self._legend_title_box,
self._legend_handle_box])
self._legend_box.set_figure(self.figure)
Expand Down Expand Up @@ -867,10 +875,41 @@ def get_texts(self):
r"""Return the list of `~.text.Text`\s in the legend."""
return silent_list('Text', self.texts)

def set_alignment(self, alignment):
"""
Set the alignment of the legend title and the box of entries.

The entries are aligned as a single block, so that markers always
lined up.

Parameters
----------
alignment : {'center', 'left', 'right'}.

"""
_api.check_in_list(["center", "left", "right"], alignment=alignment)
self._alignment = alignment
self._legend_box.align = alignment

def get_alignment(self):
"""Get the alignment value of the legend box"""
return self._legend_box.align

def set_title(self, title, prop=None):
"""
Set the legend title. Fontproperties can be optionally set
with *prop* parameter.
Set legend title and title style.

Parameters
----------
title : str
The legend title.

prop : `.font_manager.FontProperties` or `str` or `pathlib.Path`
The font properties of the legend title.
If a `str`, it is interpreted as a fontconfig pattern parsed by
`.FontProperties`. If a `pathlib.Path`, it is interpreted as the
absolute path to a font file.

"""
self._legend_title_box._text.set_text(title)
if title:
Expand Down
19 changes: 19 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,25 @@ def test_legend_title_fontprop_fontsize():
assert leg5.get_title().get_fontsize() == 20


@pytest.mark.parametrize('alignment', ('center', 'left', 'right'))
def test_legend_alignment(alignment):
fig, ax = plt.subplots()
ax.plot(range(10), label='test')
leg = ax.legend(title="Aardvark", alignment=alignment)
assert leg.get_children()[0].align == alignment
assert leg.get_alignment() == alignment


@pytest.mark.parametrize('alignment', ('center', 'left', 'right'))
def test_legend_set_alignment(alignment):
fig, ax = plt.subplots()
ax.plot(range(10), label='test')
leg = ax.legend()
leg.set_alignment(alignment)
assert leg.get_children()[0].align == alignment
assert leg.get_alignment() == alignment


@pytest.mark.parametrize('color', ('red', 'none', (.5, .5, .5)))
def test_legend_labelcolor_single(color):
# test labelcolor for a single color
Expand Down