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
7 changes: 7 additions & 0 deletions doc/users/next_whats_new/rename_ncol_keyword_in_legend.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
``ncol`` keyword argument to ``legend`` renamed to ``ncols``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The ``ncol`` keyword argument to `~.Axes.legend` for controlling the number of
columns is renamed to ``ncols`` for consistency with the ``ncols`` and
``nrows`` keywords of `~.Figure.subplots` and `~.GridSpec`.
``ncol`` is still supported though.
6 changes: 3 additions & 3 deletions lib/matplotlib/backends/qt_editor/figureoptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,12 @@ def apply_callback(data):
# re-generate legend, if checkbox is checked
if generate_legend:
draggable = None
ncol = 1
ncols = 1
if axes.legend_ is not None:
old_legend = axes.get_legend()
draggable = old_legend._draggable is not None
ncol = old_legend._ncol
new_legend = axes.legend(ncol=ncol)
ncols = old_legend._ncols
new_legend = axes.legend(ncols=ncols)
if new_legend:
new_legend.set_draggable(draggable)

Expand Down
29 changes: 19 additions & 10 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,12 @@ def _update_bbox_to_anchor(self, loc_in_canvas):

loc='upper right', bbox_to_anchor=(0.5, 0.5)

ncol : int, default: 1
ncols : int, default: 1
The number of columns that the legend has.

For backward compatibility, the spelling *ncol* is also supported
but it is discouraged. If both are given, *ncols* takes precedence.

prop : None or `matplotlib.font_manager.FontProperties` or dict
The font properties of the legend. If None (default), the current
:data:`matplotlib.rcParams` will be used.
Expand Down Expand Up @@ -317,7 +320,7 @@ def __init__(
borderaxespad=None, # pad between the axes and legend border
columnspacing=None, # spacing between columns

ncol=1, # number of columns
ncols=1, # number of columns
mode=None, # horizontal distribution of columns: None or "expand"

fancybox=None, # True: fancy box, False: rounded box, None: rcParam
Expand All @@ -333,6 +336,8 @@ def __init__(
frameon=None, # draw frame
handler_map=None,
title_fontproperties=None, # properties for the legend title
*,
ncol=1 # synonym for ncols (backward compatibility)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do this? I think you have to leave ncol where it was for backcompat? We should prob move all of these to kwarg only...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If someone uses this with a positional argument it will be picked up as ncols, so that should be fine. ncols will also come earlier when editors pop up the list of arguments, so I think this is really the way to go.

As #23166 is in, we are on the way to keyword only arguments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops yes I agree.

):
"""
Parameters
Expand Down Expand Up @@ -418,8 +423,8 @@ def val_or_rc(val, rc_name):

handles = list(handles)
if len(handles) < 2:
ncol = 1
self._ncol = ncol
ncols = 1
self._ncols = ncols if ncols != 1 else ncol

if self.numpoints <= 0:
raise ValueError("numpoints must be > 0; it was %d" % numpoints)
Expand Down Expand Up @@ -581,6 +586,10 @@ def _set_loc(self, loc):
self.stale = True
self._legend_box.set_offset(self._findoffset)

def set_ncols(self, ncols):
"""Set the number of columns."""
self._ncols = ncols

def _get_loc(self):
return self._loc_real

Expand Down Expand Up @@ -767,12 +776,12 @@ def _init_legend_box(self, handles, labels, markerfirst=True):
handles_and_labels.append((handlebox, textbox))

columnbox = []
# array_split splits n handles_and_labels into ncol columns, with the
# first n%ncol columns having an extra entry. filter(len, ...) handles
# the case where n < ncol: the last ncol-n columns are empty and get
# filtered out.
for handles_and_labels_column \
in filter(len, np.array_split(handles_and_labels, self._ncol)):
# array_split splits n handles_and_labels into ncols columns, with the
# first n%ncols columns having an extra entry. filter(len, ...)
# handles the case where n < ncols: the last ncols-n columns are empty
# and get filtered out.
for handles_and_labels_column in filter(
len, np.array_split(handles_and_labels, self._ncols)):
# pack handlebox and labelbox into itembox
itemboxes = [HPacker(pad=0,
sep=self.handletextpad * fontsize,
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4013,7 +4013,7 @@ def test_hist_stacked_bar():
fig, ax = plt.subplots()
ax.hist(d, bins=10, histtype='barstacked', align='mid', color=colors,
label=labels)
ax.legend(loc='upper right', bbox_to_anchor=(1.0, 1.0), ncol=1)
ax.legend(loc='upper right', bbox_to_anchor=(1.0, 1.0), ncols=1)


def test_hist_barstacked_bottom_unchanged():
Expand Down
15 changes: 12 additions & 3 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import numpy as np
import pytest

from matplotlib.testing.decorators import image_comparison
from matplotlib.testing.decorators import check_figures_equal, image_comparison
from matplotlib.testing._markers import needs_usetex
import matplotlib.pyplot as plt
import matplotlib as mpl
Expand Down Expand Up @@ -148,7 +148,7 @@ def test_fancy():
plt.errorbar(np.arange(10), np.arange(10), xerr=0.5,
yerr=0.5, label='XX')
plt.legend(loc="center left", bbox_to_anchor=[1.0, 0.5],
ncol=2, shadow=True, title="My legend", numpoints=1)
ncols=2, shadow=True, title="My legend", numpoints=1)


@image_comparison(['framealpha'], remove_text=True,
Expand Down Expand Up @@ -190,7 +190,7 @@ def test_legend_expand():
ax.plot(x, x - 50, 'o', label='y=-1')
l2 = ax.legend(loc='right', mode=mode)
ax.add_artist(l2)
ax.legend(loc='lower left', mode=mode, ncol=2)
ax.legend(loc='lower left', mode=mode, ncols=2)


@image_comparison(['hatching'], remove_text=True, style='default')
Expand Down Expand Up @@ -926,3 +926,12 @@ def test_legend_markers_from_line2d():

assert markers == new_markers == _markers
assert labels == new_labels


@check_figures_equal()
def test_ncol_ncols(fig_test, fig_ref):
# Test that both ncol and ncols work
strings = ["a", "b", "c", "d", "e", "f"]
ncols = 3
fig_test.legend(strings, ncol=ncols)
fig_ref.legend(strings, ncols=ncols)
2 changes: 1 addition & 1 deletion lib/matplotlib/tests/test_offsetbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def test_expand_with_tight_layout():
d2 = [2, 1]
ax.plot(d1, label='series 1')
ax.plot(d2, label='series 2')
ax.legend(ncol=2, mode='expand')
ax.legend(ncols=2, mode='expand')

fig.tight_layout() # where the crash used to happen

Expand Down