Skip to content
Merged
13 changes: 12 additions & 1 deletion lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ def __init__(self, parent, handles, labels,
raise TypeError("Legend needs either Axes or Figure as parent")
self.parent = parent

self._loc_used_default = loc is None
if loc is None:
loc = rcParams["legend.loc"]
if not self.isaxes and loc in [0, 'best']:
Expand Down Expand Up @@ -568,7 +569,10 @@ def __init__(self, parent, handles, labels,
else:
self.get_frame().set_alpha(framealpha)

self._loc = loc
tmp = self._loc_used_default
self._set_loc(loc)
self._loc_used_default = tmp # ignore changes done by _set_loc

# figure out title fontsize:
if title_fontsize is None:
title_fontsize = rcParams['legend.title_fontsize']
Expand All @@ -592,6 +596,7 @@ def _set_loc(self, loc):
# find_offset function will be provided to _legend_box and
# _legend_box will draw itself at the location of the return
# value of the find_offset.
self._loc_used_default = False
self._loc_real = loc
self.stale = True
self._legend_box.set_offset(self._findoffset)
Expand Down Expand Up @@ -1108,6 +1113,12 @@ def _find_best_position(self, width, height, renderer, consider=None):
assert self.isaxes

verts, bboxes, lines, offsets = self._auto_legend_data()
if self._loc_used_default and verts.shape[0] > 200000:
# this size results in a 3+ second render time on a good machine
cbook._warn_external(
'Creating legend with loc="best" can be slow with large '
'amounts of data.'
)

bbox = Bbox.from_bounds(0, 0, width, height)
if consider is None:
Expand Down
26 changes: 26 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from matplotlib.legend_handler import HandlerTuple
import matplotlib.legend as mlegend
from matplotlib.cbook.deprecation import MatplotlibDeprecationWarning
from matplotlib import rc_context


def test_legend_ordereddict():
Expand Down Expand Up @@ -563,3 +564,28 @@ def test_alpha_handles():
lh.set_alpha(1.0)
assert lh.get_facecolor()[:-1] == hh[1].get_facecolor()[:-1]
assert lh.get_edgecolor()[:-1] == hh[1].get_edgecolor()[:-1]


def test_warn_big_data_best_loc():
fig, ax = plt.subplots()
ax.plot(np.arange(200001), label='Is this big data?')
with pytest.warns(UserWarning) as records:
with rc_context({'legend.loc': 'best'}):
l = ax.legend()
fig.canvas.draw()
# The _find_best_position method of Legend is called twice, duplicating
# the warning message.
assert len(records) == 2
for record in records:
assert str(record.message) == (
'Creating legend with loc="best" can be slow with large'
' amounts of data.')


def test_no_warn_big_data_when_loc_specified():
fig, ax = plt.subplots()
ax.plot(np.arange(200001), label='Is this big data?')
with pytest.warns(None) as records:
l = ax.legend('best')
fig.canvas.draw()
assert len(records) == 0