Skip to content
Closed
21 changes: 14 additions & 7 deletions lib/matplotlib/legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ def _auto_legend_data(self):
List of `.Path` corresponding to each line.
offsets
List of (x, y) offsets of all collection.
texts
List of the axes bounding boxes of all texts.
"""
assert self.isaxes # always holds, as this is only called internally
ax = self.parent
Expand All @@ -838,7 +840,11 @@ def _auto_legend_data(self):
_, transOffset, hoffsets, _ = handle._prepare_points()
for offset in transOffset.transform(hoffsets):
offsets.append(offset)
return bboxes, lines, offsets

texts = [text.get_window_extent()
for text in ax.texts]

return bboxes, lines, offsets, texts

def get_children(self):
# docstring inherited
Expand Down Expand Up @@ -1011,7 +1017,7 @@ def _find_best_position(self, width, height, renderer, consider=None):

start_time = time.perf_counter()

bboxes, lines, offsets = self._auto_legend_data()
bboxes, lines, offsets, texts = self._auto_legend_data()

bbox = Bbox.from_bounds(0, 0, width, height)
if consider is None:
Expand All @@ -1027,11 +1033,12 @@ def _find_best_position(self, width, height, renderer, consider=None):
# XXX TODO: If markers are present, it would be good to take them
# into account when checking vertex overlaps in the next line.
badness = (sum(legendBox.count_contains(line.vertices)
for line in lines)
+ legendBox.count_contains(offsets)
+ legendBox.count_overlaps(bboxes)
+ sum(line.intersects_bbox(legendBox, filled=False)
for line in lines))
for line in lines) +
legendBox.count_contains(offsets) +
legendBox.count_overlaps(bboxes) +
legendBox.count_overlaps(texts) +
sum(line.intersects_bbox(legendBox, filled=False)
for line in lines))
if badness == 0:
return l, b
# Include the index to favor lower codes in case of a tie.
Expand Down
35 changes: 35 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -570,3 +570,38 @@ def test_no_warn_big_data_when_loc_specified():
ax.plot(np.arange(5000), label=idx)
legend = ax.legend('best')
fig.draw_artist(legend) # Check that no warning is emitted.


def test_overlap_no_texts():
# test there is no error without text
fig, ax = plt.subplots()
fig.canvas.draw()
legend = ax.legend()
fig.draw_artist(legend)


def test_overlap_one_text():
# test legend doesn't overlap with one text
fig, ax = plt.subplots()
fig.canvas.draw()
ax.text(1, 0, "Text")
legend = ax.legend()
fig.draw_artist(legend)
texts = [text.get_window_extent()
for text in ax.texts]

assert legend.get_window_extent().count_overlaps(texts) == 0


def test_overlap_two_texts():
# test legend doesn't overlap with two texts
fig, ax = plt.subplots()
fig.canvas.draw()
ax.text(1, 0, "Text")
ax.text(0, 1, "Text")
legend = ax.legend()
fig.draw_artist(legend)
texts = [text.get_window_extent()
for text in ax.texts]

assert legend.get_window_extent().count_overlaps(texts) == 0