diff --git a/doc/users/colors.rst b/doc/users/colors.rst index 18a5756f0ab5..d08861bccec0 100644 --- a/doc/users/colors.rst +++ b/doc/users/colors.rst @@ -17,6 +17,10 @@ it can be provided as: * a name from the `xkcd color survey `__ prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``) * one of ``{'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'}`` +* one of ``{'tab:blue', 'tab:orange', 'tab:green', + 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', + 'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the + 'T10' categorical palette (which is the default color cycle). All string specifications of color are case-insensitive. diff --git a/doc/users/dflt_style_changes.rst b/doc/users/dflt_style_changes.rst index 125a95892f7e..34aaddaf02c5 100644 --- a/doc/users/dflt_style_changes.rst +++ b/doc/users/dflt_style_changes.rst @@ -32,8 +32,13 @@ Colors in default property cycle -------------------------------- The colors in the default property cycle have been changed from -``['b', 'g', 'r', 'c', 'm', 'y', 'k']`` to the `Vega category10 palette -`__ +``['b', 'g', 'r', 'c', 'm', 'y', 'k']`` to the category10 +color palette used by `Vega +`__ and +`d3 +`__ +originally developed at Tableau. + .. plot:: diff --git a/lib/matplotlib/_color_data.py b/lib/matplotlib/_color_data.py index 11a538f34722..7c47eca30378 100644 --- a/lib/matplotlib/_color_data.py +++ b/lib/matplotlib/_color_data.py @@ -1,6 +1,6 @@ from __future__ import (absolute_import, division, print_function, unicode_literals) - +from collections import OrderedDict import six @@ -15,6 +15,24 @@ 'w': (1, 1, 1)} +# These colors are from Tableau +TABLEAU_COLORS = OrderedDict(( + ('blue', '#1f77b4'), + ('orange', '#ff7f0e'), + ('green', '#2ca02c'), + ('red', '#d62728'), + ('purple', '#9467bd'), + ('brown', '#8c564b'), + ('pink', '#e377c2'), + ('gray', '#7f7f7f'), + ('olive', '#bcbd22'), + ('cyan', '#17becf')) +) + +# Normalize name to "tab:" to avoid name collisions. +TABLEAU_COLORS = OrderedDict( + ('tab:' + name, value) for name, value in TABLEAU_COLORS.items()) + # This mapping of color names -> hex values is taken from # a survey run by Randel Monroe see: # http://blog.xkcd.com/2010/05/03/color-survey-results/ @@ -973,7 +991,6 @@ 'green': '#15b01a', 'purple': '#7e1e9c'} - # Normalize name to "xkcd:" to avoid name collisions. XKCD_COLORS = {'xkcd:' + name: value for name, value in XKCD_COLORS.items()} diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 2825c33fe97f..ee1b41e17757 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -66,7 +66,7 @@ import numpy as np from numpy import ma import matplotlib.cbook as cbook -from ._color_data import BASE_COLORS, CSS4_COLORS, XKCD_COLORS +from ._color_data import BASE_COLORS, TABLEAU_COLORS, CSS4_COLORS, XKCD_COLORS class _ColorMapping(dict): @@ -86,7 +86,14 @@ def __delitem__(self, key, value): _colors_full_map = {} # Set by reverse priority order. _colors_full_map.update(XKCD_COLORS) +_colors_full_map.update({k.replace('grey', 'gray'): v + for k, v in XKCD_COLORS.items() + if 'grey' in k}) _colors_full_map.update(CSS4_COLORS) +_colors_full_map.update(TABLEAU_COLORS) +_colors_full_map.update({k.replace('gray', 'grey'): v + for k, v in TABLEAU_COLORS.items() + if 'gray' in k}) _colors_full_map.update(BASE_COLORS) _colors_full_map = _ColorMapping(_colors_full_map) @@ -253,7 +260,7 @@ def to_hex(c, keep_alpha=False): ### Backwards-compatible color-conversion API cnames = CSS4_COLORS -COLOR_NAMES = {'xkcd': XKCD_COLORS, 'css4': CSS4_COLORS} +COLOR_NAMES = {'xkcd': XKCD_COLORS, 'css4': CSS4_COLORS, 'tc': TABLEAU_COLORS} hexColorPattern = re.compile("\A#[a-fA-F0-9]{6}\Z") @@ -404,7 +411,7 @@ class Colormap(object): """ def __init__(self, name, N=256): - r""" + """ Parameters ---------- name : str diff --git a/lib/matplotlib/tests/test_colors.py b/lib/matplotlib/tests/test_colors.py index 4f9c44c16ccf..233616ccb65e 100644 --- a/lib/matplotlib/tests/test_colors.py +++ b/lib/matplotlib/tests/test_colors.py @@ -571,9 +571,10 @@ def angled_plane(azimuth, elevation, angle, x, y): assert_array_almost_equal(h, np.cos(np.radians(angle))) -def test_xkcd(): +def test_color_names(): assert mcolors.to_hex("blue") == "#0000ff" assert mcolors.to_hex("xkcd:blue") == "#0343df" + assert mcolors.to_hex("tab:blue") == "#1f77b4" def _sph2cart(theta, phi): @@ -643,6 +644,23 @@ def test_conversions(): hex_color) +def test_grey_gray(): + color_mapping = mcolors._colors_full_map + for k in color_mapping.keys(): + if 'grey' in k: + assert color_mapping[k] == color_mapping[k.replace('grey', 'gray')] + if 'gray' in k: + assert color_mapping[k] == color_mapping[k.replace('gray', 'grey')] + + +def test_tableau_order(): + dflt_cycle = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', + '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', + '#bcbd22', '#17becf'] + + assert list(mcolors.TABLEAU_COLORS.values()) == dflt_cycle + + if __name__ == '__main__': import nose nose.runmodule(argv=['-s', '--with-doctest'], exit=False)