diff --git a/doc/devel/testing.rst b/doc/devel/testing.rst index 0f8ba4346837..5a0662f2d1ae 100644 --- a/doc/devel/testing.rst +++ b/doc/devel/testing.rst @@ -73,7 +73,7 @@ example, here is a test from :mod:`matplotlib.tests.test_basic`:: Nose determines which functions are tests by searching for functions beginning with "test" in their name. -If the test as side effects that need to be cleaned up, such as +If the test has side effects that need to be cleaned up, such as creating figures using the pyplot interface, use the ``@cleanup`` decorator:: diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 087cd90f13a7..b1e7d96fa10d 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -108,7 +108,7 @@ class Legend(Artist): 'upper center' : 9, 'center' : 10, - loc can be a tuple of the noramilzed coordinate values with + loc can be a tuple of the normalized coordinate values with respect its parent. """ @@ -729,7 +729,6 @@ def _auto_legend_data(self): assert self.isaxes ax = self.parent - vertices = [] bboxes = [] lines = [] @@ -750,6 +749,11 @@ def _auto_legend_data(self): transform = handle.get_transform() bboxes.append(handle.get_path().get_extents(transform)) + try: + vertices = np.concatenate([l.vertices for l in lines]) + except ValueError: + vertices = np.array([]) + return [vertices, bboxes, lines] def draw_frame(self, b): @@ -915,10 +919,11 @@ def _find_best_position(self, width, height, renderer, consider=None): verts, bboxes, lines = self._auto_legend_data() bbox = Bbox.from_bounds(0, 0, width, height) - consider = [self._get_anchored_bbox(x, bbox, self.get_bbox_to_anchor(), - renderer) - for x - in range(1, len(self.codes))] + if consider is None: + consider = [self._get_anchored_bbox(x, bbox, + self.get_bbox_to_anchor(), + renderer) + for x in range(1, len(self.codes))] #tx, ty = self.legendPatch.get_x(), self.legendPatch.get_y() @@ -926,9 +931,19 @@ def _find_best_position(self, width, height, renderer, consider=None): for l, b in consider: legendBox = Bbox.from_bounds(l, b, width, height) badness = 0 + # XXX TODO: If markers are present, it would be good to + # take their into account when checking vertex overlaps in + # the next line. badness = legendBox.count_contains(verts) badness += legendBox.count_overlaps(bboxes) for line in lines: + # FIXME: the following line is ill-suited for lines + # that 'spiral' around the center, because the bbox + # may intersect with the legend even if the line + # itself doesn't. One solution would be to break up + # the line into its straight-segment components, but + # this may (or may not) result in a significant + # slowdown if lines with many vertices are present. if line.intersects_bbox(legendBox): badness += 1 diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf new file mode 100644 index 000000000000..dfc06c42b71b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png new file mode 100644 index 000000000000..34f1c4d951d8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg new file mode 100644 index 000000000000..455b5fd9abe1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf index 2dd7b3df0a83..7dca7d511169 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf and b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png index aee83850ecae..85f568f6e945 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg index 3805a4cda425..1d0fcaf3c143 100644 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg +++ b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg @@ -1,7 +1,7 @@ - + - + - + @@ -587,7 +587,7 @@ Q26.2656 6.10938 33.4062 6.10938 Q40.5312 6.10938 44.6094 11.75 Q48.6875 17.3906 48.6875 27.2969" id="BitstreamVeraSans-Roman-70"/> - + diff --git a/lib/matplotlib/tests/test_legend.py b/lib/matplotlib/tests/test_legend.py index f192fb4b23af..93740044cd3d 100644 --- a/lib/matplotlib/tests/test_legend.py +++ b/lib/matplotlib/tests/test_legend.py @@ -26,6 +26,19 @@ def test_legend_auto2(): ax.legend([b1[0], b2[0]], ['up', 'down'], loc=0) +@image_comparison(baseline_images=['legend_auto3']) +def test_legend_auto3(): + 'Test automatic legend placement' + fig = plt.figure() + ax = fig.add_subplot(111) + x = [0.9, 0.1, 0.1, 0.9, 0.9, 0.5] + y = [0.95, 0.95, 0.05, 0.05, 0.5, 0.5] + ax.plot(x, y, 'o-', label='line') + ax.set_xlim(0.0, 1.0) + ax.set_ylim(0.0, 1.0) + ax.legend(loc=0) + + @image_comparison(baseline_images=['legend_various_labels'], remove_text=True) def test_various_labels(): # tests all sorts of label types @@ -34,7 +47,7 @@ def test_various_labels(): ax.plot(range(4), 'o', label=1) ax.plot(np.linspace(4, 4.1), 'o', label=u'D\xe9velopp\xe9s') ax.plot(range(4, 1, -1), 'o', label='__nolegend__') - ax.legend(numpoints=1) + ax.legend(numpoints=1, loc=0) @image_comparison(baseline_images=['fancy'], remove_text=True) diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 4c0f3d32337b..fe20ef4df55f 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -645,7 +645,7 @@ def count_contains(self, vertices): dy0 = np.sign(vertices[:, 1] - y0) dx1 = np.sign(vertices[:, 0] - x1) dy1 = np.sign(vertices[:, 1] - y1) - inside = (abs(dx0 + dx1) + abs(dy0 + dy1)) <= 2 + inside = ((abs(dx0 + dx1) + abs(dy0 + dy1)) == 0) return np.sum(inside) def count_overlaps(self, bboxes):