From 3df886b0f58b94c4bdf9f5f93a370370b1ad9812 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sun, 10 Jun 2018 09:48:07 +0200 Subject: [PATCH] Properly position markers in step plots. While it may appear costly to recache the path at every draw, this only occurs when using step plots with markers (a relatively rare case) and is still better than before the bug was introduced, when step plots used to need to be recomputed at every draw, regardless of whether markers are present. --- lib/matplotlib/lines.py | 22 ++++++++++++++++++---- lib/matplotlib/tests/test_lines.py | 14 ++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index b9769574dc90..4bd773aead91 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -739,8 +739,8 @@ def draw(self, renderer): subslice = slice(max(i0 - 1, 0), i1 + 1) self.ind_offset = subslice.start self._transform_path(subslice) - - transf_path = self._get_transformed_path() + else: + subslice = None if self.get_path_effects(): from matplotlib.patheffects import PathEffectRenderer @@ -748,7 +748,8 @@ def draw(self, renderer): renderer.open_group('line2d', self.get_gid()) if self._lineStyles[self._linestyle] != '_draw_nothing': - tpath, affine = transf_path.get_transformed_path_and_affine() + tpath, affine = (self._get_transformed_path() + .get_transformed_path_and_affine()) if len(tpath.vertices): gc = renderer.new_gc() self._set_gc_clip(gc) @@ -796,7 +797,20 @@ def draw(self, renderer): gc.set_foreground(ec_rgba, isRGBA=True) marker = self._marker - tpath, affine = transf_path.get_transformed_points_and_affine() + + # Markers *must* be drawn ignoring the drawstyle (but don't pay the + # recaching if drawstyle is already "default"). + if self.get_drawstyle() != "default": + with cbook._setattr_cm( + self, _drawstyle="default", _transformed_path=None): + self.recache() + self._transform_path(subslice) + tpath, affine = (self._get_transformed_path() + .get_transformed_path_and_affine()) + else: + tpath, affine = (self._get_transformed_path() + .get_transformed_path_and_affine()) + if len(tpath.vertices): # subsample the markers if markevery is not None markevery = self.get_markevery() diff --git a/lib/matplotlib/tests/test_lines.py b/lib/matplotlib/tests/test_lines.py index c0f4665fc1e8..a1ba6e764188 100644 --- a/lib/matplotlib/tests/test_lines.py +++ b/lib/matplotlib/tests/test_lines.py @@ -1,6 +1,8 @@ """ Tests specific to the lines module. """ + +from io import BytesIO import itertools import matplotlib.lines as mlines import pytest @@ -195,3 +197,15 @@ def test_nan_is_sorted(): assert line._is_sorted(np.array([1, 2, 3])) assert line._is_sorted(np.array([1, np.nan, 3])) assert not line._is_sorted([3, 5] + [np.nan] * 100 + [0, 2]) + + +def test_step_markers(): + fig, ax = plt.subplots() + ax.step([0, 1], "-o") + buf1 = BytesIO() + fig.savefig(buf1) + fig, ax = plt.subplots() + ax.plot([0, 0, 1], [0, 1, 1], "-o", markevery=[0, 2]) + buf2 = BytesIO() + fig.savefig(buf2) + assert buf1.getvalue() == buf2.getvalue()