diff --git a/examples/pylab_examples/color_demo.py b/examples/pylab_examples/color_demo.py index 1d471b0086a9..f67569ac9f22 100755 --- a/examples/pylab_examples/color_demo.py +++ b/examples/pylab_examples/color_demo.py @@ -1,6 +1,6 @@ #!/usr/bin/env python """ -matplotlib gives you 4 ways to specify colors, +matplotlib gives you 5 ways to specify colors, 1) as a single letter string, ala MATLAB @@ -11,6 +11,9 @@ 4) as a string representing a floating point number from 0 to 1, corresponding to shades of gray. + 5) as a special color "Cn", where n is a number 0-9 specifying the + nth color in the currently active color cycle. + See help(colors) for more info. """ import matplotlib.pyplot as plt @@ -20,8 +23,8 @@ #subplot(111, facecolor='#ababab') t = np.arange(0.0, 2.0, 0.01) s = np.sin(2*np.pi*t) -plt.plot(t, s, 'y') -plt.xlabel('time (s)', color='r') +plt.plot(t, s, 'C1') +plt.xlabel('time (s)', color='C1') plt.ylabel('voltage (mV)', color='0.5') # grayscale color plt.title('About as silly as it gets, folks', color='#afeeee') plt.show() diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index 3ea8f26dcd61..0671a1a34385 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -4,6 +4,7 @@ from matplotlib.externals import six from matplotlib.externals.six.moves import reduce, xrange, zip, zip_longest +import itertools import math import warnings @@ -2458,7 +2459,7 @@ def pie(self, x, explode=None, labels=None, colors=None, Call signature:: pie(x, explode=None, labels=None, - colors=('b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'), + colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None, counterclock=True, wedgeprops=None, textprops=None, @@ -2478,7 +2479,8 @@ def pie(self, x, explode=None, labels=None, colors=None, *colors*: [ *None* | color sequence ] A sequence of matplotlib color args through which the pie chart - will cycle. + will cycle. If `None`, will use the colors in the currently + active cycle. *labels*: [ *None* | len(x) sequence of strings ] A sequence of strings providing the labels for each wedge @@ -2567,7 +2569,12 @@ def pie(self, x, explode=None, labels=None, colors=None, if len(x) != len(explode): raise ValueError("'explode' must be of length 'x'") if colors is None: - colors = ('b', 'g', 'r', 'c', 'm', 'y', 'k', 'w') + get_next_color = self._get_patches_for_fill.get_next_color + else: + color_cycle = itertools.cycle(colors) + + def get_next_color(): + return six.next(color_cycle) if radius is None: radius = 1 @@ -2603,7 +2610,7 @@ def pie(self, x, explode=None, labels=None, colors=None, w = mpatches.Wedge((x, y), radius, 360. * min(theta1, theta2), 360. * max(theta1, theta2), - facecolor=colors[i % len(colors)], + facecolor=get_next_color(), **wedgeprops) slices.append(w) self.add_patch(w) @@ -3023,8 +3030,8 @@ def xywhere(xs, ys, mask): l0, = self.plot(x, y, fmt, label='_nolegend_', **kwargs) if ecolor is None: - if l0 is None and 'color' in self._get_lines._prop_keys: - ecolor = next(self._get_lines.prop_cycler)['color'] + if l0 is None: + ecolor = self._get_lines.get_next_color() else: ecolor = l0.get_color() @@ -3846,7 +3853,10 @@ def scatter(self, x, y, s=None, c=None, marker='o', cmap=None, norm=None, if facecolors is not None: c = facecolors else: - c = 'b' # The original default + if rcParams['_internal.classic_mode']: + c = 'b' # The original default + else: + c = self._get_patches_for_fill.get_next_color() if edgecolors is None and not rcParams['_internal.classic_mode']: edgecolors = 'face' @@ -6019,9 +6029,8 @@ def _normalize_input(inp, ename='input'): raise ValueError( 'weights should have the same shape as x') - if color is None and 'color' in self._get_lines._prop_keys: - color = [next(self._get_lines.prop_cycler)['color'] - for i in xrange(nx)] + if color is None: + color = [self._get_lines.get_next_color() for i in xrange(nx)] else: color = mcolors.colorConverter.to_rgba_array(color) if len(color) != nx: @@ -7507,6 +7516,12 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, perp_lines = self.vlines par_lines = self.hlines + if rcParams['_internal.classic_mode']: + fillcolor = 'y' + edgecolor = 'r' + else: + fillcolor = edgecolor = self._get_lines.get_next_color() + # Render violins bodies = [] for stats, pos, width in zip(vpstats, positions, widths): @@ -7517,7 +7532,7 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, bodies += [fill(stats['coords'], -vals + pos, vals + pos, - facecolor='y', + facecolor=fillcolor, alpha=0.3)] means.append(stats['mean']) mins.append(stats['min']) @@ -7527,20 +7542,24 @@ def violin(self, vpstats, positions=None, vert=True, widths=0.5, # Render means if showmeans: - artists['cmeans'] = perp_lines(means, pmins, pmaxes, colors='r') + artists['cmeans'] = perp_lines(means, pmins, pmaxes, + colors=edgecolor) # Render extrema if showextrema: - artists['cmaxes'] = perp_lines(maxes, pmins, pmaxes, colors='r') - artists['cmins'] = perp_lines(mins, pmins, pmaxes, colors='r') - artists['cbars'] = par_lines(positions, mins, maxes, colors='r') + artists['cmaxes'] = perp_lines(maxes, pmins, pmaxes, + colors=edgecolor) + artists['cmins'] = perp_lines(mins, pmins, pmaxes, + colors=edgecolor) + artists['cbars'] = par_lines(positions, mins, maxes, + colors=edgecolor) # Render medians if showmedians: artists['cmedians'] = perp_lines(medians, pmins, pmaxes, - colors='r') + colors=edgecolor) return artists diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index c11bb9c3af33..79084dc377da 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -52,6 +52,7 @@ def _process_plot_format(fmt): * 'ko': black circles * '.b': blue dots * 'r--': red dashed lines + * 'C2--': the third color in the color cycle, dashed lines .. seealso:: @@ -97,7 +98,9 @@ def _process_plot_format(fmt): chars = [c for c in fmt] - for c in chars: + i = 0 + while i < len(chars): + c = chars[i] if c in mlines.lineStyles: if linestyle is not None: raise ValueError( @@ -113,9 +116,14 @@ def _process_plot_format(fmt): raise ValueError( 'Illegal format string "%s"; two color symbols' % fmt) color = c + elif c == 'C' and i < len(chars) - 1: + color_cycle_number = int(chars[i + 1]) + color = mcolors.colorConverter._get_nth_color(color_cycle_number) + i += 1 else: raise ValueError( 'Unrecognized character %c in format string' % c) + i += 1 if linestyle is None and marker is None: linestyle = rcParams['lines.linestyle'] @@ -161,6 +169,10 @@ def set_prop_cycle(self, *args, **kwargs): else: prop_cycler = cycler(*args, **kwargs) + # Make sure the cycler always has at least one color + if 'color' not in prop_cycler.keys: + prop_cycler = prop_cycler * cycler('color', ['k']) + self.prop_cycler = itertools.cycle(prop_cycler) # This should make a copy self._prop_keys = prop_cycler.keys @@ -186,6 +198,12 @@ def __call__(self, *args, **kwargs): ret = self._grab_next_args(*args, **kwargs) return ret + def get_next_color(self): + """ + Return the next color in the cycle. + """ + return six.next(self.prop_cycler)['color'] + def set_lineprops(self, line, **kwargs): assert self.command == 'plot', 'set_lineprops only works with "plot"' line.set(**kwargs) diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index 86011f06c23f..c3555585838a 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -31,6 +31,12 @@ - k: black - w: white +To use the colors that are part of the active color cycle in the current style, +use `C` followed by a digit. For example: + + - `C0`: The first color in the cycle + - `C1`: The second color in the cycle + Gray shades can be given as a string encoding a float in the 0-1 range, e.g.:: color = '0.75' @@ -67,6 +73,19 @@ def is_color_like(c): 'Return *True* if *c* can be converted to *RGB*' + + # Special-case the N-th color cycle syntax, because its parsing + # needs to be deferred. We may be reading a value from rcParams + # here before the color_cycle rcParam has been parsed. + if isinstance(c, bytes): + match = re.match(b'^C[0-9]$', c) + if match is not None: + return True + elif isinstance(c, six.text_type): + match = re.match('^C[0-9]$', c) + if match is not None: + return True + try: colorConverter.to_rgb(c) return True @@ -114,9 +133,36 @@ class ColorConverter(object): 'k': (0, 0, 0), 'w': (1, 1, 1)} + _prop_cycler = None + cache = {} CN_LOOKUPS = [COLOR_NAMES[k] for k in ['css4', 'xkcd']] + @classmethod + def _get_nth_color(cls, val): + """ + Get the Nth color in the current color cycle. If N is greater + than the number of colors in the cycle, it is wrapped around. + """ + from matplotlib.rcsetup import cycler + from matplotlib import rcParams + + prop_cycler = rcParams['axes.prop_cycle'] + if prop_cycler is None and 'axes.color_cycle' in rcParams: + clist = rcParams['axes.color_cycle'] + prop_cycler = cycler('color', clist) + + colors = prop_cycler._transpose()['color'] + return colors[val % len(colors)] + + @classmethod + def _parse_nth_color(cls, val): + match = re.match('^C[0-9]$', val) + if match is not None: + return cls._get_nth_color(int(val[1])) + + raise ValueError("Not a color cycle color") + def to_rgb(self, arg): """ Returns an *RGB* tuple of three floats from 0-1. @@ -154,6 +200,10 @@ def to_rgb(self, arg): argl = arg.lower() color = self.colors.get(argl, None) if color is None: + try: + argl = self._parse_nth_color(arg) + except ValueError: + pass for cmapping in self.CN_LOOKUPS: str1 = cmapping.get(argl, argl) if str1 != argl: diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 9e46fefcbd3e..6f34c402499e 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -848,7 +848,7 @@ def validate_animation_writer_path(p): # line props 'lines.linewidth': [2.5, validate_float], # line width in points 'lines.linestyle': ['-', six.text_type], # solid line - 'lines.color': ['b', validate_color], # blue + 'lines.color': ['C0', validate_color], # first color in color cycle 'lines.marker': ['None', six.text_type], # black 'lines.markeredgewidth': [1.0, validate_float], 'lines.markersize': [6, validate_float], # markersize, in points @@ -867,7 +867,7 @@ def validate_animation_writer_path(p): ## patch props 'patch.linewidth': [None, validate_float_or_None], # line width in points 'patch.edgecolor': ['k', validate_color], # black - 'patch.facecolor': ['#1f77b4', validate_color], # blue (first color in color cycle) + 'patch.facecolor': ['C0', validate_color], # first color in color cycle 'patch.antialiased': [True, validate_bool], # antialiased (no jaggies) ## Histogram properties @@ -885,7 +885,7 @@ def validate_animation_writer_path(p): 'boxplot.showfliers': [True, validate_bool], 'boxplot.meanline': [False, validate_bool], - 'boxplot.flierprops.color': ['b', validate_color], + 'boxplot.flierprops.color': ['C0', validate_color], 'boxplot.flierprops.marker': ['+', six.text_type], 'boxplot.flierprops.markerfacecolor': ['auto', validate_color_or_auto], 'boxplot.flierprops.markeredgecolor': ['k', validate_color], @@ -893,11 +893,11 @@ def validate_animation_writer_path(p): 'boxplot.flierprops.linestyle': ['none', six.text_type], 'boxplot.flierprops.linewidth': [1.0, validate_float], - 'boxplot.boxprops.color': ['b', validate_color], + 'boxplot.boxprops.color': ['C0', validate_color], 'boxplot.boxprops.linewidth': [1.0, validate_float], 'boxplot.boxprops.linestyle': ['-', six.text_type], - 'boxplot.whiskerprops.color': ['b', validate_color], + 'boxplot.whiskerprops.color': ['C0', validate_color], 'boxplot.whiskerprops.linewidth': [1.0, validate_float], 'boxplot.whiskerprops.linestyle': ['--', six.text_type], @@ -905,7 +905,7 @@ def validate_animation_writer_path(p): 'boxplot.capprops.linewidth': [1.0, validate_float], 'boxplot.capprops.linestyle': ['-', six.text_type], - 'boxplot.medianprops.color': ['r', validate_color], + 'boxplot.medianprops.color': ['C1', validate_color], 'boxplot.medianprops.linewidth': [1.0, validate_float], 'boxplot.medianprops.linestyle': ['-', six.text_type], @@ -1016,7 +1016,10 @@ def validate_animation_writer_path(p): 'axes.formatter.use_mathtext': [False, validate_bool], 'axes.formatter.useoffset': [True, validate_bool], 'axes.unicode_minus': [True, validate_bool], - 'axes.color_cycle': [['b', 'g', 'r', 'c', 'm', 'y', 'k'], + 'axes.color_cycle': [ + ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', + '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', + '#bcbd22', '#17becf'], deprecate_axes_colorcycle], # cycle of plot # line colors # This entry can be either a cycler object or a diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py index 423884723461..41d3e04a308d 100755 --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -45,6 +45,7 @@ from matplotlib.transforms import Affine2D from matplotlib import verbose from matplotlib import docstring +from matplotlib import rcParams __author__ = "Kevin L. Davies" __credits__ = ["Yannick Copin"] @@ -770,11 +771,15 @@ def _get_angle(a, r): print("lrpath\n", self._revert(lrpath)) xs, ys = list(zip(*vertices)) self.ax.plot(xs, ys, 'go-') - patch = PathPatch(Path(vertices, codes), - fc=kwargs.pop('fc', kwargs.pop('facecolor', - '#bfd1d4')), # Custom defaults - lw=kwargs.pop('lw', kwargs.pop('linewidth', 0.5)), - **kwargs) + if rcParams['_internal.classic_mode']: + fc = kwargs.pop('fc', kwargs.pop('facecolor', '#bfd1d4')) + lw = kwargs.pop('lw', kwargs.pop('linewidth', 0.5)) + else: + fc = kwargs.pop('fc', kwargs.pop('facecolor', None)) + lw = kwargs.pop('lw', kwargs.pop('linewidth', None)) + if fc is None: + fc = six.next(self.ax._get_patches_for_fill.prop_cycler)['color'] + patch = PathPatch(Path(vertices, codes), fc=fc, lw=lw, **kwargs) self.ax.add_patch(patch) # Add the path labels. diff --git a/lib/matplotlib/stackplot.py b/lib/matplotlib/stackplot.py index 8a34f97c389a..e44885953373 100644 --- a/lib/matplotlib/stackplot.py +++ b/lib/matplotlib/stackplot.py @@ -108,10 +108,7 @@ def stackplot(axes, x, *args, **kwargs): raise ValueError(errstr) # Color between x = 0 and the first array. - if 'color' in axes._get_lines._prop_keys: - color = six.next(axes._get_lines.prop_cycler)['color'] - else: - color = None + color = axes._get_lines.get_next_color() r.append(axes.fill_between(x, first_line, stack[0, :], facecolor=color, label= six.next(labels, None), @@ -120,10 +117,7 @@ def stackplot(axes, x, *args, **kwargs): # Color between array i-1 and array i for i in xrange(len(y) - 1): - if 'color' in axes._get_lines._prop_keys: - color = six.next(axes._get_lines.prop_cycler)['color'] - else: - color = None + color = axes._get_lines.get_next_color() r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :], facecolor=color, label= six.next(labels, None), diff --git a/lib/matplotlib/streamplot.py b/lib/matplotlib/streamplot.py index 64db899104d2..51409fad6828 100644 --- a/lib/matplotlib/streamplot.py +++ b/lib/matplotlib/streamplot.py @@ -82,8 +82,8 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None, if transform is None: transform = axes.transData - if color is None and 'color' in axes._get_lines._prop_keys: - color = six.next(axes._get_lines.prop_cycler)['color'] + if color is None: + color = axes._get_lines.get_next_color() if linewidth is None: linewidth = matplotlib.rcParams['lines.linewidth'] diff --git a/lib/matplotlib/tests/baseline_images/test_cycles/lineprop_cycle_basic.png b/lib/matplotlib/tests/baseline_images/test_cycles/lineprop_cycle_basic.png index e3706c3216f2..2d20423df44d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_cycles/lineprop_cycle_basic.png and b/lib/matplotlib/tests/baseline_images/test_cycles/lineprop_cycle_basic.png differ diff --git a/lib/mpl_toolkits/mplot3d/axes3d.py b/lib/mpl_toolkits/mplot3d/axes3d.py index 1e2fc5b19829..283c17c6ea4d 100755 --- a/lib/mpl_toolkits/mplot3d/axes3d.py +++ b/lib/mpl_toolkits/mplot3d/axes3d.py @@ -1593,7 +1593,10 @@ def plot_surface(self, X, Y, Z, *args, **kwargs): if 'facecolors' in kwargs: fcolors = kwargs.pop('facecolors') else: - color = np.array(colorConverter.to_rgba(kwargs.pop('color', 'b'))) + color = kwargs.pop('color', None) + if color is None: + color = self._get_lines.get_next_color() + color = np.array(colorConverter.to_rgba(color)) fcolors = None cmap = kwargs.get('cmap', None) @@ -1862,7 +1865,10 @@ def plot_trisurf(self, *args, **kwargs): had_data = self.has_data() # TODO: Support custom face colours - color = np.array(colorConverter.to_rgba(kwargs.pop('color', 'b'))) + color = kwargs.pop('color', None) + if color is None: + color = self._get_lines.get_next_color() + color = np.array(colorConverter.to_rgba(color)) cmap = kwargs.get('cmap', None) norm = kwargs.pop('norm', None) @@ -2211,7 +2217,7 @@ def add_collection3d(self, col, zs=0, zdir='z'): Axes.add_collection(self, col) - def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', depthshade=True, + def scatter(self, xs, ys, zs=0, zdir='z', s=20, c=None, depthshade=True, *args, **kwargs): ''' Create a scatter plot. @@ -2264,6 +2270,8 @@ def scatter(self, xs, ys, zs=0, zdir='z', s=20, c='b', depthshade=True, s = np.ma.ravel(s) # This doesn't have to match x, y in size. + if c is None: + c = self._get_lines.get_next_color() cstr = cbook.is_string_like(c) or cbook.is_sequence_of_strings(c) if not cstr: c = np.asanyarray(c) @@ -2342,7 +2350,7 @@ def bar(self, left, height, zs=0, zdir='z', *args, **kwargs): return patches - def bar3d(self, x, y, z, dx, dy, dz, color='b', + def bar3d(self, x, y, z, dx, dy, dz, color=None, zsort='average', *args, **kwargs): ''' Generate a 3D bar, or multiple bars. diff --git a/matplotlibrc.template b/matplotlibrc.template index ed220657175d..1ddb3fcd0dd2 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -80,7 +80,7 @@ backend : $TEMPLATE_BACKEND # information on line properties. #lines.linewidth : 2.0 # line width in points #lines.linestyle : - # solid line -#lines.color : blue # has no affect on plot(); see axes.prop_cycle +#lines.color : C0 # has no affect on plot(); see axes.prop_cycle #lines.marker : None # the default marker #lines.markeredgewidth : 1.0 # the line width around the marker symbol #lines.markersize : 6 # markersize, in points @@ -105,7 +105,7 @@ backend : $TEMPLATE_BACKEND #patch.linewidth : None # edge width in points. # If None, use axes.linewidth when patch # is not filled. -#patch.facecolor : 1f77b4 +#patch.facecolor : C0 #patch.edgecolor : black #patch.antialiased : True # render patches in antialiased (no jaggies) @@ -141,14 +141,14 @@ backend : $TEMPLATE_BACKEND #boxplot.capprops.linewidth : 1.0 #boxplot.capprops.linestyle : '-' -#boxplot.medianprops.color : 'b' +#boxplot.medianprops.color : 'C0' #boxplot.medianprops.linewidth : 1.0 #boxplot.medianprops.linestyle : '-' -#boxplot.meanprops.color : 'b' +#boxplot.meanprops.color : 'C1' #boxplot.meanprops.marker : '^' -#boxplot.meanprops.markerfacecolor : 'b' -#boxplot.meanprops.markeredgecolor : 'b' +#boxplot.meanprops.markerfacecolor : 'C1' +#boxplot.meanprops.markeredgecolor : 'C1' #boxplot.meanprops.markersize : 6 #boxplot.meanprops.linestyle : 'none' #boxplot.meanprops.linewidth : 1.0 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy