Skip to content

Commit aa96f2d

Browse files
committed
Support Cn colors with n>=10.
While the change is mildly backwards-incompatible (as noted in the API changes), Cn syntax is by far the simplest way to navigate the color-cycle, so I think the change is worth it.
1 parent 9e8be5b commit aa96f2d

File tree

7 files changed

+56
-39
lines changed

7 files changed

+56
-39
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
``Cn`` colors now support ``n>=10``
2+
```````````````````````````````````
3+
4+
It is now possible to go beyond the tenth color in the property cycle using
5+
``Cn`` syntax, e.g. ``plt.plot([1, 2], color="C11")`` now uses the 12th color
6+
in the cycle.
7+
8+
Note that previously, a construct such as ``plt.plot([1, 2], "C11")`` would be
9+
interpreted as a request to use color ``C1`` and marker ``1`` (an "inverted Y").
10+
To obtain such a plot, one should now use ``plt.plot([1, 2], "1C1")`` (so that
11+
the first "1" gets correctly interpreted as a marker specification), or, more
12+
explicitly, ``plt.plot([1, 2], marker="1", color="C1")``.

examples/color/color_demo.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Color Demo
44
==========
55
6-
Matplotlib gives you 8 ways to specify colors,
6+
Matplotlib recognizes the following formats to specify a color:
77
88
1) an RGB or RGBA tuple of float values in ``[0, 1]`` (e.g. ``(0.1, 0.2, 0.5)``
99
or ``(0.1, 0.2, 0.5, 0.3)``). RGBA is short for Red, Green, Blue, Alpha;
@@ -15,10 +15,10 @@
1515
5) a X11/CSS4 ("html") color name, e.g. ``"blue"``;
1616
6) a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__,
1717
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
18-
7) a "Cn" color spec, i.e. `'C'` followed by a single digit, which is an index
19-
into the default property cycle
20-
(``matplotlib.rcParams['axes.prop_cycle']``); the indexing occurs at artist
21-
creation time and defaults to black if the cycle does not include color.
18+
7) a "Cn" color spec, i.e. `'C'` followed by a number, which is an index into
19+
the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``); the
20+
indexing is intended to occur at rendering time, and defaults to black if
21+
the cycle does not include color.
2222
8) one of ``{'tab:blue', 'tab:orange', 'tab:green',
2323
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
2424
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the

lib/matplotlib/axes/_axes.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,32 +1517,14 @@ def plot(self, *args, scalex=True, scaley=True, **kwargs):
15171517
15181518
A format string consists of a part for color, marker and line::
15191519
1520-
fmt = '[color][marker][line]'
1520+
fmt = '[marker][line][color]'
15211521
15221522
Each of them is optional. If not provided, the value from the style
15231523
cycle is used. Exception: If ``line`` is given, but no ``marker``,
15241524
the data will be a line without markers.
15251525
1526-
**Colors**
1527-
1528-
The following color abbreviations are supported:
1529-
1530-
============= ===============================
1531-
character color
1532-
============= ===============================
1533-
``'b'`` blue
1534-
``'g'`` green
1535-
``'r'`` red
1536-
``'c'`` cyan
1537-
``'m'`` magenta
1538-
``'y'`` yellow
1539-
``'k'`` black
1540-
``'w'`` white
1541-
============= ===============================
1542-
1543-
If the color is the only part of the format string, you can
1544-
additionally use any `matplotlib.colors` spec, e.g. full names
1545-
(``'green'``) or hex strings (``'#008000'``).
1526+
Other combinations such as ``[color][marker][line]`` are also
1527+
supported, but note that their parsing may be ambiguous.
15461528
15471529
**Markers**
15481530
@@ -1587,11 +1569,33 @@ def plot(self, *args, scalex=True, scaley=True, **kwargs):
15871569
Example format strings::
15881570
15891571
'b' # blue markers with default shape
1590-
'ro' # red circles
1591-
'g-' # green solid line
1572+
'or' # red circles
1573+
'-g' # green solid line
15921574
'--' # dashed line with default color
1593-
'k^:' # black triangle_up markers connected by a dotted line
1575+
'^k:' # black triangle_up markers connected by a dotted line
15941576
1577+
**Colors**
1578+
1579+
The supported color abbreviations are the single letter codes
1580+
1581+
============= ===============================
1582+
character color
1583+
============= ===============================
1584+
``'b'`` blue
1585+
``'g'`` green
1586+
``'r'`` red
1587+
``'c'`` cyan
1588+
``'m'`` magenta
1589+
``'y'`` yellow
1590+
``'k'`` black
1591+
``'w'`` white
1592+
============= ===============================
1593+
1594+
and the ``'CN'`` colors that index into the default property cycle.
1595+
1596+
If the color is the only part of the format string, you can
1597+
additionally use any `matplotlib.colors` spec, e.g. full names
1598+
(``'green'``) or hex strings (``'#008000'``).
15951599
"""
15961600
lines = []
15971601

lib/matplotlib/colors.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
5050
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the
5151
'T10' categorical palette (which is the default color cycle);
52-
* a "CN" color spec, i.e. `'C'` followed by a single digit, which is an index
53-
into the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``);
54-
the indexing occurs at artist creation time and defaults to black if the
52+
* a "CN" color spec, i.e. `'C'` followed by a number, which is an index into
53+
the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``); the
54+
indexing is intended to occur at rendering time, and defaults to black if the
5555
cycle does not include color.
5656
5757
All string specifications of color, other than "CN", are case-insensitive.
@@ -115,7 +115,7 @@ def _sanitize_extrema(ex):
115115

116116
def _is_nth_color(c):
117117
"""Return whether *c* can be interpreted as an item in the color cycle."""
118-
return isinstance(c, str) and re.match(r"\AC[0-9]\Z", c)
118+
return isinstance(c, str) and re.match(r"\AC[0-9]+\Z", c)
119119

120120

121121
def is_color_like(c):
@@ -169,7 +169,7 @@ def to_rgba(c, alpha=None):
169169
from matplotlib import rcParams
170170
prop_cycler = rcParams['axes.prop_cycle']
171171
colors = prop_cycler.by_key().get('color', ['k'])
172-
c = colors[int(c[1]) % len(colors)]
172+
c = colors[int(c[1:]) % len(colors)]
173173
try:
174174
rgba = _colors_full_map.cache[c, alpha]
175175
except (KeyError, TypeError): # Not in cache, or unhashable.

lib/matplotlib/tests/test_colors.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,8 @@ def test_cn():
637637
['xkcd:blue', 'r'])
638638
assert mcolors.to_hex("C0") == '#0343df'
639639
assert mcolors.to_hex("C1") == '#ff0000'
640+
assert mcolors.to_hex("C10") == '#0343df'
641+
assert mcolors.to_hex("C11") == '#ff0000'
640642

641643
matplotlib.rcParams['axes.prop_cycle'] = cycler('color', ['8e4585', 'r'])
642644

lib/matplotlib/tests/test_rcparams.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,14 @@ def generate_validator_testcases(valid):
306306
('AABBCC', '#AABBCC'), # RGB hex code
307307
('AABBCC00', '#AABBCC00'), # RGBA hex code
308308
('tab:blue', 'tab:blue'), # named color
309-
('C0', 'C0'), # color from cycle
309+
('C12', 'C12'), # color from cycle
310310
('(0, 1, 0)', [0.0, 1.0, 0.0]), # RGB tuple
311311
((0, 1, 0), (0, 1, 0)), # non-string version
312312
('(0, 1, 0, 1)', [0.0, 1.0, 0.0, 1.0]), # RGBA tuple
313313
((0, 1, 0, 1), (0, 1, 0, 1)), # non-string version
314314
('(0, 1, "0.5")', [0.0, 1.0, 0.5]), # unusual but valid
315315
),
316316
'fail': (('tab:veryblue', ValueError), # invalid name
317-
('C123', ValueError), # invalid RGB(A) code and cycle index
318317
('(0, 1)', ValueError), # tuple with length < 3
319318
('(0, 1, 0, 1, 0)', ValueError), # tuple with length > 4
320319
('(0, 1, none)', ValueError), # cannot cast none to float

tutorials/colors/colors.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
1919
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the
2020
'T10' categorical palette (which is the default color cycle);
21-
* a "CN" color spec, i.e. `'C'` followed by a single digit, which is an index
22-
into the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``);
23-
the indexing occurs at artist creation time and defaults to black if the
21+
* a "CN" color spec, i.e. `'C'` followed by a number, which is an index into
22+
the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``); the
23+
indexing is intended to occur at rendering time, and defaults to black if the
2424
cycle does not include color.
2525
2626
"Red", "Green" and "Blue", are the intensities of those colors, the combination

0 commit comments

Comments
 (0)