10000 Merge pull request #4686 from WeatherGod/stylecycler2 · matplotlib/matplotlib@07aff06 · GitHub
[go: up one dir, main page]

Skip to content

Commit 07aff06

Browse files
committed
Merge pull request #4686 from WeatherGod/stylecycler2
ENH: Property Cycling Cycle all artist properties, not just colors
2 parents ce3eeaa + 63d6321 commit 07aff06

33 files changed

+656
-102
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
`color_cycle` deprecated
2+
````````````````````````
3+
4+
In light of the new property cycling feature,
5+
the Axes method *set_color_cycle* is now deprecated.
6+
Calling this method will replace the current property cycle with
7+
one that cycles just the given colors.
8+
9+
Similarly, the rc parameter *axes.color_cycle* is also deprecated in
10+
lieu of the new *axes.prop_cycle* parameter. Having both parameters in
11+
the same rc file is not recommended as the result cannot be
12+
predicted. For compatibility, setting *axes.color_cycle* will
13+
replace the cycler in *axes.prop_cycle* with a color cycle.
14+
Accessing *axes.color_cycle* will return just the color portion
15+
of the property cycle, if it exists.
16+
17+
Timeline for removal has not been set.

doc/users/whats_new/rcparams.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
Added ``axes.prop_cycle`` key to rcParams
2+
`````````````````````````````````````````
3+
This is a more generic form of the now-deprecated ``axes.color_cycle`` param.
4+
Now, we can cycle more than just colors, but also linestyles, hatches,
5+
and just about any other artist property. Cycler notation is used for
6+
defining proprty cycles. Adding cyclers together will be like you are
7+
`zip()`-ing together two or more property cycles together::
8+
9+
axes.prop_cycle: cycler('color', 'rgb') + cycler('lw', [1, 2, 3])
10+
11+
You can even multiply cyclers, which is like using `itertools.product()`
12+
on two or more property cycles. Remember to use parentheses if writing
13+
a multi-line `prop_cycle` parameter.
14+
15+
..plot:: mpl_examples/color/color_cycle_demo.py
16+
117
Added ``errorbar.capsize`` key to rcParams
218
``````````````````````````````````````````
319
Controls the length of end caps on error bars. If set to zero, errorbars

examples/color/color_cycle_demo.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
"""
2-
Demo of custom color-cycle settings to control colors for multi-line plots.
2+
Demo of custom property-cycle settings to control colors and such
3+
for multi-line plots.
34
45
This example demonstrates two different APIs:
56
6-
1. Setting the default rc-parameter specifying the color cycle.
7-
This affects all subsequent plots.
8-
2. Setting the color cycle for a specific axes. This only affects a single
9-
axes.
7+
1. Setting the default rc-parameter specifying the property cycle.
8+
This affects all subsequent axes (but not axes already created).
9+
2. Setting the property cycle for a specific axes. This only
10+
affects a single axes.
1011
"""
12+
from cycler import cycler
1113
import numpy as np
1214
import matplotlib.pyplot as plt
1315

@@ -17,13 +19,14 @@
1719
yy = np.transpose([np.sin(x + phi) for phi in offsets])
1820

1921
plt.rc('lines', linewidth=4)
22+
plt.rc('axes', prop_cycle=(cycler('color', ['r', 'g', 'b', 'y']) +
23+
cycler('linestyle', ['-', '--', ':', '-.'])))
2024
fig, (ax0, ax1) = plt.subplots(nrows=2)
21-
22-
plt.rc('axes', color_cycle=['r', 'g', 'b', 'y'])
2325
ax0.plot(yy)
2426
ax0.set_title('Set default color cycle to rgby')
2527

26-
ax1.set_color_cycle(['c', 'm', 'y', 'k'])
28+
ax1.set_prop_cycle(cycler('color', ['c', 'm', 'y', 'k']) +
29+
cycler('lw', [1, 2, 3, 4]))
2730
ax1.plot(yy)
2831
ax1.set_title('Set axes color cycle to cmyk')
2932

lib/matplotlib/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@
121121
from matplotlib.cbook import is_string_like, mplDeprecation
122122
from matplotlib.compat import subprocess
123123
from matplotlib.rcsetup import (defaultParams,
124-
validate_backend)
124+
validate_backend,
125+
cycler)
125126

126127
import numpy
127128
from matplotlib.externals.six.moves.urllib.request import urlopen
@@ -826,6 +827,8 @@ def matplotlib_fname():
826827
'svg.embed_char_paths': ('svg.fonttype',
827828
lambda x: "path" if x else "none", None),
828829
'savefig.extension': ('savefig.format', lambda x: x, None),
830+
'axes.color_cycle': ('axes.prop_cycle', lambda x: cycler('color', x),
831+
lambda x: [c.get('color', None) for c in x]),
829832
}
830833

831834
_deprecated_ignore_map = {
@@ -1452,6 +1455,7 @@ def tk_window_focus():
14521455
'matplotlib.tests.test_transforms',
14531456
'matplotlib.tests.test_triangulation',
14541457
'matplotlib.tests.test_widgets',
1458+
'matplotlib.tests.test_cycles',
14551459
'matplotlib.sphinxext.tests.test_tinypages',
14561460
'mpl_toolkits.tests.test_mplot3d',
14571461
'mpl_toolkits.tests.test_axes_grid1',

lib/matplotlib/artist.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -920,13 +920,20 @@ def properties(self):
920920

921921
def set(self, **kwargs):
922922
"""
923-
A tkstyle set command, pass *kwargs* to set properties
923+
A property batch setter. Pass *kwargs* to set properties.
924+
Will handle property name collisions (e.g., if both
925+
'color' and 'facecolor' are specified, the property
926+
with higher priority gets set last).
927+
924928
"""
925929
ret = []
926-
for k, v in six.iteritems(kwargs):
930+
for k, v in sorted(kwargs.items(), reverse=True):
927931
k = k.lower()
928932
funcName = "set_%s" % k
929-
func = getattr(self, funcName)
933+
func = getattr(self, funcName, None)
934+
if func is None:
935+
raise TypeError('There is no %s property "%s"' %
936+
(self.__class__.__name__, k))
930937
ret.extend([func(v)])
931938
return ret
932939

@@ -1442,14 +1449,17 @@ def setp(obj, *args, **kwargs):
14421449
funcvals = []
14431450
for i in range(0, len(args) - 1, 2):
14441451
funcvals.append((args[i], args[i + 1]))
1445-
funcvals.extend(kwargs.items())
1452+
funcvals.extend(sorted(kwargs.items(), reverse=True))
14461453

14471454
ret = []
14481455
for o in objs:
14491456
for s, val in funcvals:
14501457
s = s.lower()
14511458
funcName = "set_%s" % s
1452-
func = getattr(o, funcName)
1459+
func = getattr(o, funcName, None)
1460+
if func is None:
1461+
raise TypeError('There is no %s property "%s"' %
1462+
(o.__class__.__name__, s))
14531463
ret.extend([func(val)])
14541464
return [x for x in cbook.flatten(ret)]
14551465

lib/matplotlib/axes/_axes.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,9 +1265,9 @@ def plot(self, *args, **kwargs):
12651265
12661266
Return value is a list of lines that were added.
12671267
1268-
By default, each line is assigned a different color specified by a
1269-
'color cycle'. To change this behavior, you can edit the
1270-
axes.color_cycle rcParam.
1268+
By default, each line is assigned a different style specified by a
1269+
'style cycle'. To change this behavior, you can edit the
1270+
axes.prop_cycle rcParam.
12711271
12721272
The following format string characters are accepted to control
12731273
the line style or marker:
@@ -2949,8 +2949,8 @@ def xywhere(xs, ys, mask):
29492949
l0, = self.plot(x, y, fmt, **kwargs)
29502950

29512951
if ecolor is None:
2952-
if l0 is None:
2953-
ecolor = six.next(self._get_lines.color_cycle)
2952+
if l0 is None and 'color' in self._get_lines._prop_keys:
2953+
ecolor = six.next(self._get_lines.prop_cycler)['color']
29542954
else:
29552955
ecolor = l0.get_color()
29562956

@@ -5843,8 +5843,8 @@ def hist(self, x, bins=10, range=None, normed=False, weights=None,
58435843

58445844
nx = len(x) # number of datasets
58455845

5846-
if color is None:
5847-
color = [six.next(self._get_lines.color_cycle)
5846+
if color is None and 'color' in self._get_lines._prop_keys:
5847+
color = [six.next(self._get_lines.prop_cycler)['color']
58485848
for i in xrange(nx)]
58495849
else:
58505850
color = mcolors.colorConverter.to_rgba_array(color)
3193

0 commit comments

Comments
 (0)
0