Skip to content

Commit 7a9552f

Browse files
committed
Support markevery on figure-level lines.
... except for `markevery=<float>` or `(<float>, <float>)` which is a spec relative to the axes size (keeping handling of that specific case into _mark_every_path).
1 parent 57489bf commit 7a9552f

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

lib/matplotlib/lines.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def segment_hits(cx, cy, x, y, radius):
104104
return np.concatenate((points, lines))
105105

106106

107-
def _mark_every_path(markevery, tpath, affine, ax_transform):
107+
def _mark_every_path(markevery, tpath, affine, ax):
108108
"""
109109
Helper function that sorts out how to deal the input
110110
`markevery` and returns the points where markers should be drawn.
@@ -152,6 +152,10 @@ def _slice_or_none(in_v, slc):
152152
'`markevery` is a tuple with len 2 and second element is '
153153
'a float, but the first element is not a float or an int; '
154154
'markevery={}'.format(markevery))
155+
if ax is None:
156+
raise ValueError(
157+
"markevery is specified relative to the axes size, but "
158+
"the line does not have a Axes as parent")
155159
# calc cumulative distance along path (in display coords):
156160
disp_coords = affine.transform(tpath.vertices)
157161
delta = np.empty((len(disp_coords), 2))
@@ -160,7 +164,7 @@ def _slice_or_none(in_v, slc):
160164
delta = np.hypot(*delta.T).cumsum()
161165
# calc distance between markers along path based on the axes
162166
# bounding box diagonal being a distance of unity:
163-
(x0, y0), (x1, y1) = ax_transform.transform([[0, 0], [1, 1]])
167+
(x0, y0), (x1, y1) = ax.transAxes.transform([[0, 0], [1, 1]])
164168
scale = np.hypot(x1 - x0, y1 - y0)
165169
marker_delta = np.arange(start * scale, delta[-1], step * scale)
166170
# find closest actual data point that is closest to
@@ -812,8 +816,8 @@ def draw(self, renderer):
812816
# subsample the markers if markevery is not None
813817
markevery = self.get_markevery()
814818
if markevery is not None:
815-
subsampled = _mark_every_path(markevery, tpath,
816-
affine, self.axes.transAxes)
819+
subsampled = _mark_every_path(
820+
markevery, tpath, affine, self.axes)
817821
else:
818822
subsampled = tpath
819823

lib/matplotlib/tests/test_lines.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -217,28 +217,57 @@ def test_step_markers(fig_test, fig_ref):
217217
fig_ref.subplots().plot([0, 0, 1], [0, 1, 1], "-o", markevery=[0, 2])
218218

219219

220+
@pytest.mark.parametrize("parent", ["figure", "axes"])
220221
@check_figures_equal(extensions=('png',))
221-
def test_markevery(fig_test, fig_ref):
222+
def test_markevery(fig_test, fig_ref, parent):
222223
np.random.seed(42)
223-
t = np.linspace(0, 3, 14)
224-
y = np.random.rand(len(t))
224+
x = np.linspace(0, 1, 14)
225+
y = np.random.rand(len(x))
225226

226-
casesA = [None, 4, (2, 5), [1, 5, 11],
227-
[0, -1], slice(5, 10, 2), 0.3, (0.3, 0.4),
228-
np.arange(len(t))[y > 0.5]]
229-
casesB = ["11111111111111", "10001000100010", "00100001000010",
230-
"01000100000100", "10000000000001", "00000101010000",
231-
"11011011011110", "01010011011101", "01110001110110"]
227+
cases_test = [None, 4, (2, 5), [1, 5, 11],
228+
[0, -1], slice(5, 10, 2),
229+
np.arange(len(x))[y > 0.5],
230+
0.3, (0.3, 0.4)]
231+
cases_ref = ["11111111111111", "10001000100010", "00100001000010",
232+
"01000100000100", "10000000000001", "00000101010000",
233+
"01110001110110", "11011011011110", "01010011011101"]
232234

233-
axsA = fig_ref.subplots(3, 3)
234-
axsB = fig_test.subplots(3, 3)
235+
if parent == "figure":
236+
# float markevery ("relative to axes size") is not supported.
237+
cases_test = cases_test[:-2]
238+
cases_ref = cases_ref[:-2]
235239

236-
for ax, case in zip(axsA.flat, casesA):
237-
ax.plot(t, y, "-gD", markevery=case)
240+
def add_test(x, y, *, markevery):
241+
fig_test.add_artist(
242+
mlines.Line2D(x, y, marker="o", markevery=markevery))
238243

239-
for ax, case in zip(axsB.flat, casesB):
244+
def add_ref(x, y, *, markevery):
245+
fig_ref.add_artist(
246+
mlines.Line2D(x, y, marker="o", markevery=markevery))
247+
248+
elif parent == "axes":
249+
axs_test = iter(fig_test.subplots(3, 3).flat)
250+
axs_ref = iter(fig_ref.subplots(3, 3).flat)
251+
252+
def add_test(x, y, *, markevery):
253+
next(axs_test).plot(x, y, "-gD", markevery=markevery)
254+
255+
def add_ref(x, y, *, markevery):
256+
next(axs_ref).plot(x, y, "-gD", markevery=markevery)
257+
258+
for case in cases_test:
259+
add_test(x, y, markevery=case)
260+
261+
for case in cases_ref:
240262
me = np.array(list(case)).astype(int).astype(bool)
241-
ax.plot(t, y, "-gD", markevery=me)
263+
add_ref(x, y, markevery=me)
264+
265+
266+
def test_markevery_figure_line_unsupported_relsize():
267+
fig = plt.figure()
268+
fig.add_artist(mlines.Line2D([0, 1], [0, 1], marker="o", markevery=.5))
269+
with pytest.raises(ValueError):
270+
fig.canvas.draw()
242271

243272

244273
def test_marker_as_markerstyle():

0 commit comments

Comments
 (0)