Skip to content

Commit b2782e0

Browse files
authored
Merge pull request #10713 from salindersidhu/fixed-issue-8576
Implemented support for 'markevery' in prop_cycle
2 parents 8af1fac + 3154b90 commit b2782e0

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Implemented support for axes.prop_cycle property markevery in rcParams
2+
----------------------------------------------------------------------
3+
4+
The Matplotlib ``rcParams`` settings object now supports configuration
5+
of the attribute `axes.prop_cycle` with cyclers using the `markevery`
6+
Line2D object property. An example of this feature is provided at
7+
`~matplotlib/examples/lines_bars_and_markers/markevery_prop_cycle.py`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""
2+
=================================================================
3+
Implemented support for prop_cycle property markevery in rcParams
4+
=================================================================
5+
6+
This example demonstrates a working solution to issue #8576, providing full
7+
support of the markevery property for axes.prop_cycle assignments through
8+
rcParams. Makes use of the same list of markevery cases from
9+
https://matplotlib.org/examples/pylab_examples/markevery_demo.html
10+
11+
Renders a plot with shifted-sine curves along each column with
12+
a unique markevery value for each sine curve.
13+
"""
14+
from cycler import cycler
15+
import numpy as np
16+
import matplotlib as mpl
17+
import matplotlib.pyplot as plt
18+
19+
# Define a list of markevery cases and color cases to plot
20+
cases = [None,
21+
8,
22+
(30, 8),
23+
[16, 24, 30],
24+
[0, -1],
25+
slice(100, 200, 3),
26+
0.1,
27+
0.3,
28+
1.5,
29+
(0.0, 0.1),
30+
(0.45, 0.1)]
31+
32+
colors = ['#1f77b4',
33+
'#ff7f0e',
34+
'#2ca02c',
35+
'#d62728',
36+
'#9467bd',
37+
'#8c564b',
38+
'#e377c2',
39+
'#7f7f7f',
40+
'#bcbd22',
41+
'#17becf',
42+
'#1a55FF']
43+
44+
# Create two different cyclers to use with axes.prop_cycle
45+
markevery_cycler = cycler(markevery=cases)
46+
color_cycler = cycler('color', colors)
47+
48+
# Configure rcParams axes.prop_cycle with custom cycler
49+
custom_cycler = color_cycler + markevery_cycler
50+
mpl.rcParams['axes.prop_cycle'] = custom_cycler
51+
52+
# Create data points and offsets
53+
x = np.linspace(0, 2 * np.pi)
54+
offsets = np.linspace(0, 2 * np.pi, 11, endpoint=False)
55+
yy = np.transpose([np.sin(x + phi) for phi in offsets])
56+
57+
# Set the plot curve with markers and a title
58+
fig = plt.figure()
59+
ax = fig.add_axes([0.1, 0.1, 0.6, 0.75])
60+
61+
for i in range(len(cases)):
62+
ax.plot(yy[:, i], marker='o', label=str(cases[i]))
63+
ax.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.)
64+
65+
plt.title('Support for axes.prop_cycle cycler with markevery')
66+
67+
plt.show()

lib/matplotlib/rcsetup.py

+48
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,54 @@ def validate_ps_distiller(s):
534534
_validate_negative_linestyle = ValidateInStrings('negative_linestyle',
535535
['solid', 'dashed'],
536536
ignorecase=True)
537+
def validate_markevery(s):
538+
"""
539+
Validate the markevery property of a Line2D object.
540+
541+
Parameters
542+
----------
543+
s : None, int, float, slice, length-2 tuple of ints,
544+
length-2 tuple of floats, list of ints
545+
546+
Returns
547+
-------
548+
s : None, int, float, slice, length-2 tuple of ints,
549+
length-2 tuple of floats, list of ints
550+
551+
"""
552+
# Validate s against type slice
553+
if isinstance(s, slice):
554+
return s
555+
# Validate s against type tuple
556+
if isinstance(s, tuple):
557+
tupMaxLength = 2
558+
tupType = type(s[0])
559+
if len(s) != tupMaxLength:
560+
raise TypeError("'markevery' tuple must have a length of "
561+
"%d" % (tupMaxLength))
562+
if tupType is int and not all(isinstance(e, int) for e in s):
563+
raise TypeError("'markevery' tuple with first element of "
564+
"type int must have all elements of type "
565+
"int")
566+
if tupType is float and not all(isinstance(e, float) for e in s):
567+
raise TypeError("'markevery' tuple with first element of "
568+
"type float must have all elements of type "
569+
"float")
570+
if tupType is not float and tupType is not int:
571+
raise TypeError("'markevery' tuple contains an invalid type")
572+
# Validate s against type list
573+
elif isinstance(s, list):
574+
if not all(isinstance(e, int) for e in s):
575+
raise TypeError("'markevery' list must have all elements of "
576+
"type int")
577+
# Validate s against type float int and None
578+
elif not isinstance(s, (float, int)):
579+
if s is not None:
580+
raise TypeError("'markevery' is of an invalid type")
581+
582+
return s
537583

584+
validate_markeverylist = _listify_validator(validate_markevery)
538585

539586
validate_legend_loc = ValidateInStrings(
540587
'legend_loc',
@@ -676,6 +723,7 @@ def validate_hatch(s):
676723
'markersize': validate_floatlist,
677724
'markeredgewidth': validate_floatlist,
678725
'markeredgecolor': validate_colorlist,
726+
'markevery': validate_markeverylist,
679727
'alpha': validate_floatlist,
680728
'marker': validate_stringlist,
681729
'hatch': validate_hatchlist,

lib/matplotlib/tests/test_rcparams.py

+30
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
validate_cycler,
2424
validate_hatch,
2525
validate_hist_bins,
26+
validate_markevery,
2627
_validate_linestyle)
2728

2829

@@ -326,6 +327,35 @@ def generate_validator_testcases(valid):
326327
),
327328
'fail': (('aardvark', ValueError),
328329
)
330+
},
331+
{'validator': validate_markevery,
332+
'success': ((None, None),
333+
(1, 1),
334+
(0.1, 0.1),
335+
((1, 1), (1, 1)),
336+
((0.1, 0.1), (0.1, 0.1)),
337+
([1, 2, 3], [1, 2, 3]),
338+
(slice(2), slice(None, 2, None)),
339+
(slice(1, 2, 3), slice(1, 2, 3))
340+
),
341+
'fail': (((1, 2, 3), TypeError),
342+
([1, 2, 0.3], TypeError),
343+
(['a', 2, 3], TypeError),
344+
([1, 2, 'a'], TypeError),
345+
((0.1, 0.2, 0.3), TypeError),
346+
((0.1, 2, 3), TypeError),
347+
((1, 0.2, 0.3), TypeError),
348+
((1, 0.1), TypeError),
349+
((0.1, 1), TypeError),
350+
(('abc'), TypeError),
351+
((1, 'a'), TypeError),
352+
((0.1, 'b'), TypeError),
353+
(('a', 1), TypeError),
354+
(('a', 0.1), TypeError),
355+
('abc', TypeError),
356+
('a', TypeError),
357+
(object(), TypeError)
358+
)
329359
}
330360
)
331361

0 commit comments

Comments
 (0)