Skip to content

Commit 5702999

Browse files
authored
Merge pull request #12455 from kbrose/warn-on-legend-slowness
Warn when "best" loc of legend is used with lots of data
2 parents 1c374ff + f89a78c commit 5702999

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

lib/matplotlib/legend.py

+12-1
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ def __init__(self, parent, handles, labels,
484484
raise TypeError("Legend needs either Axes or Figure as parent")
485485
self.parent = parent
486486

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

571-
self._loc = loc
572+
tmp = self._loc_used_default
573+
self._set_loc(loc)
574+
self._loc_used_default = tmp # ignore changes done by _set_loc
575+
572576
# figure out title fontsize:
573577
if title_fontsize is None:
574578
title_fontsize = rcParams['legend.title_fontsize']
@@ -592,6 +596,7 @@ def _set_loc(self, loc):
592596
# find_offset function will be provided to _legend_box and
593597
# _legend_box will draw itself at the location of the return
594598
# value of the find_offset.
599+
self._loc_used_default = False
595600
self._loc_real = loc
596601
self.stale = True
597602
self._legend_box.set_offset(self._findoffset)
@@ -1108,6 +1113,12 @@ def _find_best_position(self, width, height, renderer, consider=None):
11081113
assert self.isaxes
11091114

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

11121123
bbox = Bbox.from_bounds(0, 0, width, height)
11131124
if consider is None:

lib/matplotlib/tests/test_legend.py

+26
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from matplotlib.legend_handler import HandlerTuple
1414
import matplotlib.legend as mlegend
1515
from matplotlib.cbook.deprecation import MatplotlibDeprecationWarning
16+
from matplotlib import rc_context
1617

1718

1819
def test_legend_ordereddict():
@@ -545,3 +546,28 @@ def test_alpha_handles():
545546
lh.set_alpha(1.0)
546547
assert lh.get_facecolor()[:-1] == hh[1].get_facecolor()[:-1]
547548
assert lh.get_edgecolor()[:-1] == hh[1].get_edgecolor()[:-1]
549+
550+
551+
def test_warn_big_data_best_loc():
552+
fig, ax = plt.subplots()
553+
ax.plot(np.arange(200001), label='Is this big data?')
554+
with pytest.warns(UserWarning) as records:
555+
with rc_context({'legend.loc': 'best'}):
556+
l = ax.legend()
557+
fig.canvas.draw()
558+
# The _find_best_position method of Legend is called twice, duplicating
559+
# the warning message.
560+
assert len(records) == 2
561+
for record in records:
562+
assert str(record.message) == (
563+
'Creating legend with loc="best" can be slow with large'
564+
' amounts of data.')
565+
566+
567+
def test_no_warn_big_data_when_loc_specified():
568+
fig, ax = plt.subplots()
569+
ax.plot(np.arange(200001), label='Is this big data?')
570+
with pytest.warns(None) as records:
571+
l = ax.legend('best')
572+
fig.canvas.draw()
573+
assert len(records) == 0

0 commit comments

Comments
 (0)