8000 Introduce new Tableau colors · matplotlib/matplotlib@9594f19 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9594f19

Browse files
Introduce new Tableau colors
1 parent f38a600 commit 9594f19

File tree

9 files changed

+209
-69
lines changed

9 files changed

+209
-69
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
:orphan:
2+
3+
Introduce new Tableau colors
4+
----------------------------
5+
6+
In its version 10, Tableau `introduced a new palette of categorical colors
7+
<https://www.tableau.com/about/blog/2016/7/colors-upgrade-tableau-10-56782>`__.
8+
Those are now available in matplotlib with the prefix ``tabx:``:
9+
``{'tabx:blue', 'tabx:orange', 'tabx:red', 'tabx:cyan', 'tabx:green',
10+
'tabx:yellow', 'tabx:purple', 'tabx:pink', 'tabx:brown', 'tabx:grey'}``
11+
12+
Those colors are also provided as a new ``tabx10`` colormap. An additional
13+
``tabx20`` colormap with is added.
14+
15+
In general those colors are a little less saturated than those from the default
16+
color cycle. Replacing the default color cycler with those colors can e.g. be
17+
achieved via
18+
19+
::
20+
21+
cols = plt.cm.tabx10.colors
22+
plt.rcParams["axes.prop_cycle"] = plt.cycler("color", cols)}
23+
24+

examples/color/color_demo.py

Lines changed: 21 additions & 10 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 gives you 7 ways to specify colors,
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;
@@ -13,16 +13,25 @@
1313
4) a single letter string, i.e. one of
1414
``{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}``;
1515
5) a X11/CSS4 ("html") color name, e.g. ``"blue"``;
16-
6) a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__,
17-
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
16+
6) a color name from a palette, prefixed with the palette's name:
17+
18+
a. a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__;
19+
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
20+
b. one of ``{'tab:blue', 'tab:orange', 'tab:green',
21+
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
22+
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from
23+
the 'T10' categorical palette (which is the default color cycle);
24+
c. one of ``{'tabx:blue', 'tabx:orange', 'tabx:red', 'tabx:cyan',
25+
'tabx:green', 'tabx:yellow', 'tabx:purple', 'tabx:pink', 'tabx:brown',
26+
'tabx:gray' }`` which are the colors from the
27+
`new Tableau10 categorical palette
28+
<https://www.tableau.com/about/blog/2016/7/colors-upgrade-tableau-10-\
29+
56782>`__;
30+
1831
7) a "Cn" color spec, i.e. `'C'` followed by a single digit, which is an index
1932
into the default property cycle
2033
(``matplotlib.rcParams['axes.prop_cycle']``); the indexing occurs at artist
2134
creation time and defaults to black if the cycle does not include color.
22-
8) one of ``{'tab:blue', 'tab:orange', 'tab:green',
23-
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
24-
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the
25-
'tab10' categorical palette (which is the default color cycle);
2635
2736
For more information on colors in matplotlib see
2837
@@ -47,12 +56,14 @@
4756
ax.set_xlabel('time (s)', color='c')
4857
# 5) a named color:
4958
ax.set_ylabel('voltage (mV)', color='peachpuff')
50-
# 6) a named xkcd color:
59+
# 6a) a named xkcd color:
5160
ax.plot(t, s, 'xkcd:crimson')
61+
# 6b) tab notation:
62+
ax.tick_params(axis="x", labelcolor='tab:orange')
63+
# 6c) tabx notation:
64+
ax.tick_params(axis="y", labelcolor='tabx:yellow')
5265
# 7) Cn notation:
5366
ax.plot(t, .7*s, color='C4', linestyle='--')
54-
# 8) tab notation:
55-
ax.tick_params(labelcolor='tab:orange')
5667

5768

5869
plt.show()

examples/color/colormap_reference.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
('Qualitative', [
3434
'Pastel1', 'Pastel2', 'Paired', 'Accent',
3535
'Dark2', 'Set1', 'Set2', 'Set3',
36-
'tab10', 'tab20', 'tab20b', 'tab20c']),
36+
'tab10', 'tab20', 'tab20b', 'tab20c', 'tabx10', 'tabx20']),
3737
('Miscellaneous', [
3838
'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern',
3939
'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg',

examples/color/named_colors.py

Lines changed: 62 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,52 +12,70 @@
1212
* the :doc:`/gallery/color/color_demo`.
1313
"""
1414

15-
import matplotlib.pyplot as plt
16-
from matplotlib import colors as mcolors
17-
18-
19-
colors = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)
20-
21-
# Sort colors by hue, saturation, value and name.
22-
by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgba(color)[:3])), name)
23-
for name, color in colors.items())
24-
sorted_names = [name for hsv, name in by_hsv]
25-
26-
n = len(sorted_names)
27-
ncols = 4
28-
nrows = n // ncols
29-
30-
fig, ax = plt.subplots(figsize=(9, 8))
3115

32-
# Get height and width
33-
X, Y = fig.get_dpi() * fig.get_size_inches()
34-
h = Y / (nrows + 1)
35-
w = X / ncols
36-
37-
for i, name in enumerate(sorted_names):
38-
row = i % nrows
39-
col = i // nrows
40-
y = Y - (row * h) - h
41-
42-
xi_line = w * (col + 0.05)
43-
xf_line = w * (col + 0.25)
44-
xi_text = w * (col + 0.3)
45-
46-
ax.text(xi_text, y, name, fontsize=(h * 0.5),
47-
horizontalalignment='left',
48-
verticalalignment='center')
49-
50-
ax.hlines(y + h * 0.1, xi_line, xf_line,
51-
color=colors[name], linewidth=(h * 0.6))
52-
53-
ax.set_xlim(0, X)
54-
ax.set_ylim(0, Y)
55-
ax.set_axis_off()
16+
import matplotlib.pyplot as plt
17+
import matplotlib.colors as mcolors
18+
19+
20+
def plot_colortable(colors, title, sort_colors=True, emptycols=0):
21+
22+
cell_width = 185
23+
cell_height = 24
24+
swatch_width = 38
25+
margin = 10
26+
topmargin = 30
27+
28+
# Sort colors by hue, saturation, value and name.
29+
by_hsv = ((tuple(mcolors.rgb_to_hsv(mcolors.to_rgba(color)[:3])), name)
30+
for name, color in colors.items())
31+
if sort_colors is True:
32+
by_hsv = sorted(by_hsv)
33+
names = [name for hsv, name in by_hsv]
34+
35+
n = len(names)
36+
ncols = 4 - emptycols
37+
nrows = n // ncols + int(n % ncols > 0)
38+
39+
width = cell_width * 4 + 2 * margin
40+
height = cell_height * nrows + margin + topmargin
41+
dpi = 72
42+
43+
fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
44+
fig.subplots_adjust(margin/width, margin/height,
45+
(width-margin)/width, (height-topmargin)/height)
46+
ax.set_xlim(0, cell_width * 4)
47+
ax.set_ylim(cell_height * (nrows-0.5), -cell_height/2.)
48+
ax.yaxis.set_visible(False)
49+
ax.xaxis.set_visible(False)
50+
ax.set_axis_off()
51+
ax.set_title(title, fontsize=20, loc="left")
52+
53+
for i, name in enumerate(names):
54+
row = i % nrows
55+
col = i // nrows
56+
y = row * cell_height
57+
58+
swatch_start_x = cell_width * col
59+
swatch_end_x = cell_width * col + swatch_width
60+
text_pos_x = cell_width * col + swatch_width + 5
61+
62+
ax.text(text_pos_x, y, name, fontsize=12,
63+
horizontalalignment='left',
64+
verticalalignment='center')
65+
66+
ax.hlines(y, swatch_start_x, swatch_end_x,
67+
color=colors[name], linewidth=18)
68+
plt.show()
69+
70+
plot_colortable(mcolors.BASE_COLORS, "Base Colors",
71+
sort_colors=False, emptycols=1)
72+
plot_colortable(mcolors.TABLEAU_COLORS, "Tableau Palette",
73+ 10000
sort_colors=False, emptycols=1)
74+
plot_colortable(mcolors.TABLEAUX_COLORS, "New Tableau Palette",
75+
sort_colors=False, emptycols=1)
76+
#sphinx_gallery_thumbnail_number = 4
77+
plot_colortable(mcolors.CSS4_COLORS, "CSS Colors")
5678

57-
fig.subplots_adjust(left=0, right=1,
58-
top=1, bottom=0,
59-
hspace=0, wspace=0)
60-
plt.show()
6179

6280
#############################################################################
6381
#

lib/matplotlib/_cm.py

Lines changed: 49 additions & 0 deletions
< 10000 tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,53 @@ def _gist_yarg(x): return 1 - x
13461346
)
13471347

13481348

1349+
_tabx10colors = [
1350+
"#4e79a7", # blue
1351+
"#f28e2b", # orange
1352+
"#e15759", # red
1353+
"#76b7b2", # cyan
1354+
"#59a14f", # green
1355+
"#edc948", # yellow
1356+
"#b07aa1", # purple
1357+
"#ff9da7", # pink
1358+
"#9c755f", # brown
1359+
"#bab0ac", # grey
1360+
]
1361+
1362+
_tabx20colors = [
1363+
"#4e79a7", # blue
1364+
"#a0cbe8",
1365+
"#f28e2b", # orange
1366+
"#ffbe7d",
1367+
"#59a14f", # green
1368+
"#8cd17d",
1369+
"#b6992d", # yellow # is different from tabx10
1370+
"#f1ce63",
1371+
"#499894", # cyan # is different from tabx10
1372+
"#86bcb6",
1373+
"#e15759", # red
1374+
"#ff9d9a",
1375+
"#79706e", # grey # is different from tabx10
1376+
"#bab0ac",
1377+
"#d37295", # pink # is different from tabx10
1378+
"#fabfd2",
1379+
"#b07aa1", # purple # is different from tabx10
1380+
"#d4a6c8",
1381+
"#9d7660", # brown # is different from tabx10
1382+
"#d7b5a6",
1383+
]
1384+
1385+
_tabx10_data = []
1386+
for c in _tabx10colors:
1387+
d = [int(s, 16)/255. for s in list(map(''.join, zip(*[iter(c[1:])]*2)))]
1388+
_tabx10_data.append(d)
1389+
1390+
_tabx20_data = []
1391+
for c in _tabx20colors:
1392+
d = [int(s, 16)/255. for s in list(map(''.join, zip(*[iter(c[1:])]*2)))]
1393+
_tabx20_data.append(d)
1394+
1395+
13491396
datad = {
13501397
'Blues': _Blues_data,
13511398
'BrBG': _BrBG_data,
@@ -1423,4 +1470,6 @@ def _gist_yarg(x): return 1 - x
14231470
'tab20': {'listed': _tab20_data},
14241471
'tab20b': {'listed': _tab20b_data},
14251472
'tab20c': {'listed': _tab20c_data},
1473+
'tabx10': {'listed': _tabx10_data},
1474+
'tabx20': {'listed': _tabx20_data},
14261475
}

lib/matplotlib/_color_data.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,23 @@
3030
TABLEAU_COLORS = OrderedDict(
3131
('tab:' + name, value) for name, value in TABLEAU_COLORS)
3232

33+
# These colors are from Tableau Version 10
34+
TABLEAUX_COLORS = (
35+
("blue", "#4e79a7"),
36+
("orange", "#f28e2b"),
37+
("red", "#e15759"),
38+
("cyan", "#76b7b2"),
39+
("green", "#59a14f"),
40+
("yellow", "#edc948"),
41+
("purple", "#b07aa1"),
42+
("pink", "#ff9da7"),
43+
("brown", "#9c755f"),
44+
("gray", "#bab0ac")
45+
)
46+
# Normalize name to "tabx:<name>" to avoid name collisions.
47+
TABLEAUX_COLORS = OrderedDict(
48+
('tabx:' + name, value) for name, value in TABLEAUX_COLORS)
49+
3350
# This mapping of color names -> hex values is taken from
3451
# a survey run by Randel Monroe see:
3552
# http://blog.xkcd.com/2010/05/03/color-survey-results/

lib/matplotlib/colors.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,21 @@
4141
level (e.g., ``'0.5'``);
4242
* one of ``{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}``;
4343
* a X11/CSS4 color name;
44-
* a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__;
45-
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
46-
* one of ``{'tab:blue', 'tab:orange', 'tab:green',
47-
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
48-
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the
49-
'T10' categorical palette (which is the default color cycle);
44+
* a color name from a palette, prefixed with the palette's name:
45+
46+
* a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__;
47+
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
48+
* one of ``{'tab:blue', 'tab:orange', 'tab:green',
49+
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
50+
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from
51+
the 'T10' categorical palette (which is the default color cycle);
52+
* one of ``{'tabx:blue', 'tabx:orange', 'tabx:red', 'tabx:cyan',
53+
'tabx:green', 'tabx:yellow', 'tabx:purple', 'tabx:pink', 'tabx:brown',
54+
'tabx:gray' }`` which are the colors from the
55+
`new Tableau10 categorical palette
56+
<https://www.tableau.com/about/blog/2016/7/colors-upgrade-tableau-10-\
57+
56782>`__;
58+
5059
* a "CN" color spec, i.e. `'C'` followed by a single digit, which is an index
5160
into the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``);
5261
the indexing occurs at artist creation time and defaults to black if the
@@ -61,7 +70,8 @@
6170

6271
import numpy as np
6372
import matplotlib.cbook as cbook
64-
from ._color_data import BASE_COLORS, TABLEAU_COLORS, CSS4_COLORS, XKCD_COLORS
73+
from ._color_data import (BASE_COLORS, TABLEAU_COLORS, TABLEAUX_COLORS,
74+
CSS4_COLORS, XKCD_COLORS)
6575

6676

6777
class _ColorMapping(dict):
@@ -89,6 +99,7 @@ def __delitem__(self, key):
8999
_colors_full_map.update({k.replace('gray', 'grey'): v
90100
for k, v in TABLEAU_COLORS.items()
91101
if 'gray' in k})
102+
_colors_full_map.update(TABLEAUX_COLORS)
92103
_colors_full_map.update(BASE_COLORS)
93104
_colors_full_map = _ColorMapping(_colors_full_map)
94105

tutorials/colors/colormaps.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@
160160

161161
cmaps['Qualitative'] = ['Pastel1', 'Pastel2', 'Paired', 'Accent',
162162
'Dark2', 'Set1', 'Set2', 'Set3',
163-
'tab10', 'tab20', 'tab20b', 'tab20c']
163+
'tab10', 'tab20', 'tab20b', 'tab20c',
164+
'tabx10', 'tabx20']
164165

165166
###############################################################################
166167
# Miscellaneous

tutorials/colors/colors.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,21 @@
1212
level (e.g., ``'0.5'``);
1313
* one of ``{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}``;
1414
* a X11/CSS4 color name;
15-
* a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__;
16-
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
17-
* one of ``{'tab:blue', 'tab:orange', 'tab:green',
18-
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
19-
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the
20-
'T10' categorical palette (which is the default color cycle);
15+
* a color name from a palette, prefixed with the palette's name:
16+
17+
* a name from the `xkcd color survey <https://xkcd.com/color/rgb/>`__;
18+
prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``);
19+
* one of ``{'tab:blue', 'tab:orange', 'tab:green',
20+
'tab:red', 'tab:purple', 'tab:brown', 'tab:pink',
21+
'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from
22+
the 'T10' categorical palette (which is the default color cycle);
23+
* one of ``{'tabx:blue', 'tabx:orange', 'tabx:red', 'tabx:cyan',
24+
'tabx:green', 'tabx:yellow', 'tabx:purple', 'tabx:pink', 'tabx:brown',
25+
'tabx:gray'}`` which are the colors from the
26+
`new Tableau10 categorical palette
27+
<https://www.tableau.com/about/blog/2016/7/colors-upgrade-tableau-10-\
28+
56782>`__;
29+
2130
* a "CN" color spec, i.e. `'C'` followed by a single digit, which is an index
2231
into the default property cycle (``matplotlib.rcParams['axes.prop_cycle']``);
2332
the indexing occurs at artist creation time and defaults to black if the

0 commit comments

Comments
 (0)
0