Merge pull request #22387 from timhoffm/color-sequences · matplotlib/matplotlib@6997192 · GitHub
Skip to content

Commit 6997192

Browse files
authored
Merge pull request #22387 from timhoffm/color-sequences
Add a registry for color sequences
2 parents c358ba5 + 0abe0ce commit 6997192

7 files changed

Lines changed: 185 additions & 13 deletions

File tree

doc/api/colors_api.rst

Lines changed: 26 additions & 9 deletions

doc/api/matplotlib_configuration_api.rst

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,15 @@ Logging
5252

5353
.. autofunction:: set_loglevel
5454

55-
Colormaps
56-
=========
55+
Colormaps and color sequences
56+
=============================
5757

5858
.. autodata:: colormaps
5959
:no-value:
6060

61+
.. autodata:: color_sequences
62+
:no-value:
63+
6164
Miscellaneous
6265
=============
6366

doc/api/pyplot_summary.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,6 @@ For a more in-depth look at colormaps, see the
3131

3232
.. autodata:: colormaps
3333
:no-value:
34+
35+
.. autodata:: color_sequences
36+
:no-value:

lib/matplotlib/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,3 +1455,4 @@ def inner(ax, *args, data=None, **kwargs):
14551455
# workaround: we must defer colormaps import to after loading rcParams, because
14561456
# colormap creation depends on rcParams
14571457
from matplotlib.cm import _colormaps as colormaps
1458+
from matplotlib.colors import _color_sequences as color_sequences

lib/matplotlib/colors.py

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"""
4141

4242
import base64
43-
from collections.abc import Sized, Sequence
43+
from collections.abc import Sized, Sequence, Mapping
4444
import copy
4545
import functools
4646
import importlib
@@ -54,7 +54,7 @@
5454

5555
import matplotlib as mpl
5656
import numpy as np
57-
from matplotlib import _api, cbook, scale
57+
from matplotlib import _api, _cm, cbook, scale
5858
from ._color_data import BASE_COLORS, TABLEAU_COLORS, CSS4_COLORS, XKCD_COLORS
5959

6060

@@ -94,6 +94,113 @@ def get_named_colors_mapping():
9494
return _colors_full_map
9595

9696

97+
class ColorSequenceRegistry(Mapping):
98+
r"""
99+
Container for sequences of colors that are known to Matplotlib by name.
100+
101+
The universal registry instance is `matplotlib.color_sequences`. There
102+
should be no need for users to instantiate `.ColorSequenceRegistry`
103+
themselves.
104+
105+
Read access uses a dict-like interface mapping names to lists of colors::
106+
107+
import matplotlib as mpl
108+
cmap = mpl.color_sequences['tab10']
109+
110+
The returned lists are copies, so that their modification does not change
111+
the global definition of the color sequence.
112+
113+
Additional color sequences can be added via
114+
`.ColorSequenceRegistry.register`::
115+
116+
mpl.color_sequences.register('rgb', ['r', 'g', 'b'])
117+
"""
118+
119+
_BUILTIN_COLOR_SEQUENCES = {
120+
'tab10': _cm._tab10_data,
121+
'tab20': _cm._tab20_data,
122+
'tab20b': _cm._tab20b_data,
123+
'tab20c': _cm._tab20c_data,
124+
'Pastel1': _cm._Pastel1_data,
125+
'Pastel2': _cm._Pastel2_data,
126+
'Paired': _cm._Paired_data,
127+
'Accent': _cm._Accent_data,
128+
'Dark2': _cm._Dark2_data,
129+
'Set1': _cm._Set1_data,
130+
'Set2': _cm._Set1_data,
131+
'Set3': _cm._Set1_data,
132+
}
133+
134+
def __init__(self):
135+
self._color_sequences = {**self._BUILTIN_COLOR_SEQUENCES}
136+
137+
def __getitem__(self, item):
138+
try:
139+
return list(self._color_sequences[item])
140+
except KeyError:
141+
raise KeyError(f"{item!r} is not a known color sequence name")
142+
143+
def __iter__(self):
144+
return iter(self._color_sequences)
145+
146+
def __len__(self):
147+
return len(self._color_sequences)
148+
149+
def __str__(self):
150+
return ('ColorSequenceRegistry; available colormaps:\n' +
151+
', '.join(f"'{name}'" for name in self))
152+
153+
def register(self, name, color_list):
154+
"""
155+
Register a new color sequence.
156+
157+
The color sequence registry stores a copy of the given *color_list*, so
158+
that future changes to the original list do not affect the registered
159+
color sequence. Think of this as the registry taking a snapshot
160+
of *color_list* at registration.
161+
162+
Parameters
163+
----------
164+
name : str
165+
The name for the color sequence.
166+
167+
color_list : list of colors
168+
An iterable returning valid Matplotlib colors when iterating over.
169+
Note however that the returned color sequence will always be a
170+
list regardless of the input type.
171+
172+
"""
173+
if name in self._BUILTIN_COLOR_SEQUENCES:
174+
raise ValueError(f"{name!r} is a reserved name for a builtin "
175+
"color sequence")
176+
177+
color_list = list(color_list) # force copy and coerce type to list
178+
for color in color_list:
179+
try:
180+
to_rgba(color)
181+
except ValueError:
182+
raise ValueError(
183+
f"{color!r} is not a valid color specification")
184+
185+
self._color_sequences[name] = color_list
186+
187+
def unregister(self, name):
188+
"""
189+
Remove a sequence from the registry.
190+
191+
You cannot remove built-in color sequences.
192+
193+
If the name is not registered, returns with no error.
194+
"""
195+
if name in self._BUILTIN_COLOR_SEQUENCES:
196+
raise ValueError(
197+
f"Cannot unregister builtin color sequence {name!r}")
198+
self._color_sequences.pop(name, None)
199+
200+
201+
_color_sequences = ColorSequenceRegistry()
202+
203+
97204
def _sanitize_extrema(ex):
98205
if ex is None:
99206
return ex

lib/matplotlib/pyplot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
from matplotlib import cm
7373
from matplotlib.cm import _colormaps as colormaps, get_cmap, register_cmap
74+
from matplotlib.colors import _color_sequences as color_sequences
7475

7576
import numpy as np
7677

lib/matplotlib/tests/test_colors.py

Lines changed: 40 additions & 0 deletions

0 commit comments

Comments
 (0)