Source code for sciris.sc_colors

"""
Handle colors and colormaps.

Highlights:
    - Adds colormaps including ``'turbo'``, ``'parula'``, and ``'orangeblue'``
    - :func:`sc.hex2rgb() <hex2rgb>`/:func:`sc.rgb2hex() <rgb2hex>`: convert between different color conventions
    - :func:`sc.vectocolor() <vectocolor>`: map a list of sequential values onto a list of colors
    - :func:`sc.gridcolors() <gridcolors>`: map a list of qualitative categories onto a list of colors
"""

##############################################################################
#%% Imports
##############################################################################

import struct
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import sciris as sc


##############################################################################
#%% Color functions
##############################################################################

__all__ = ['sanitizecolor', 'shifthue', 'rgb2hex', 'hex2rgb', 'rgb2hsv', 'hsv2rgb']


def _listify_colors(colors, origndim=None):
    """ Do standard transformation on colors -- internal helper function """
    if not origndim:
        colors = sc.dcp(colors) # So we don't overwrite the original
        origndim = np.ndim(colors) # Original dimensionality
        if origndim==1:
            colors = [colors] # Wrap it in another list if needed
        colors = np.array(colors) # Just convert it to an array
        return colors, origndim
    else: # Reverse the transformation
        if origndim==1:
            colors = colors[0] # Pull it out again
        return colors


[docs] def sanitizecolor(color, asarray=False, alpha=None, normalize=True): """ Alias to :func:`matplotlib.colors.to_rgb`, but also handles numeric inputs. Arg: color (str/list/etc): the input color to sanitize into an RGB tuple (or array) asarray (bool): whether to return an array instead of a tuple alpha (float): if not None, include the alpha channel with this value normalize (bool): whether to divide by 255 if any values are greater than 1 **Examples**:: green1 = sc.sanitizecolor('g') green2 = sc.sanitizecolor('tab:green') crimson1 = sc.sanitizecolor('crimson') crimson2 = sc.sanitizecolor((220, 20, 60)) midgrey = sc.sanitizecolor(0.5) """ if isinstance(color, str): try: color = mpl.colors.to_rgb(color) except ValueError as E: errormsg = f'Could not understand "{color}" as a valid color: must be a standard Matplotlib color string' raise ValueError(errormsg) from E elif isinstance(color, float): color = [color]*3 # Consider it grey color = sc.toarray(color).astype(float) # Get it into consistent format for further operations if len(color) not in [3,4]: # pragma: no cover errormsg = f'Cannot parse {color} as a color: expecting length 3 (RGB) or 4 (RGBA)' raise ValueError(errormsg) if normalize and color.max()>1: color /= 255 if alpha is not None and len(color) == 3: color = sc.cat(color, float(alpha)) if not asarray: color = tuple(color) # Convert back to tuple if desired return color
def _processcolors(colors=None, asarray=False, ashex=False, reverse=False): """ Small helper function to do common transformations on the colors, once generated. Expects colors to be an array. If asarray is True and reverse are False, returns that array. Otherwise, does the required permutations. """ if asarray: output = colors if reverse: output = output[::-1] # Reverse the array else: output = [] for c in colors: # Gather output output.append(tuple(c)) if reverse: # Reverse the list # pragma: no cover output.reverse() if ashex: # pragma: no cover for c,color in enumerate(output): output[c] = rgb2hex(color) return output
[docs] def shifthue(colors=None, hueshift=0.0): """ Shift the hue of the colors being fed in. **Example**:: colors = sc.shifthue(colors=[(1,0,0),(0,1,0)], hueshift=0.5) """ colors, origndim = _listify_colors(colors) for c,color in enumerate(colors): color = sc.toarray(color, dtype=float) # Required for NumPy 2.0 hsvcolor = mpl.colors.rgb_to_hsv(color) hsvcolor[0] = (hsvcolor[0]+hueshift) % 1.0 # Calculate new hue and return the modulus rgbcolor = mpl.colors.hsv_to_rgb(hsvcolor) colors[c] = rgbcolor colors = _listify_colors(colors, origndim) return colors
[docs] def rgb2hex(arr): """ A little helper function to convert e.g. [0.53, 0.74, 0.15] to a pleasing shade of green. **Example**:: hx = sc.rgb2hex([0.53, 0.74, 0.15]) # Returns '#87bc26' """ arr = np.array(arr) if len(arr) != 3: # pragma: no cover errormsg = f'Cannot convert "{arr}" to hex: wrong length' raise ValueError(errormsg) if all(arr<=1): arr *= 255. # Convert from 0-1 to 0-255 hexstr = '#%02x%02x%02x' % (int(arr[0]), int(arr[1]), int(arr[2])) return hexstr
[docs] def hex2rgb(string): """ A little helper function to convert e.g. '87bc26' to a pleasing shade of green. **Example**:: rgb = sc.hex2rgb('#87bc26') # Returns array([0.52941176, 0.7372549 , 0.14901961]) """ if string[0] == '#': string = string[1:] # Trim leading #, if it exists if len(string) == 3: string = string[0]*2 + string[1]*2 + string[2]*2 # Convert e.g. '8b2' to '88bb22' if len(string) != 6: # pragma: no cover errormsg = f'Cannot convert "{string}" to an RGB color: must be 3 or 6 characters long' raise ValueError(errormsg) hexstring = bytes.fromhex(string) # Ensure it's the right type rgb = np.array(struct.unpack('BBB',hexstring),dtype=float)/255. return rgb
[docs] def rgb2hsv(colors=None): """ Shortcut to Matplotlib's rgb_to_hsv method, accepts a color triplet or a list/array of color triplets. **Example**:: hsv = sc.rgb2hsv([0.53, 0.74, 0.15]) # Returns array([0.2259887, 0.7972973, 0.74 ]) """ colors, origndim = _listify_colors(colors) for c,color in enumerate(colors): hsvcolor = mpl.colors.rgb_to_hsv(color) colors[c] = hsvcolor colors = _listify_colors(colors, origndim) return colors
[docs] def hsv2rgb(colors=None): """ Shortcut to Matplotlib's hsv_to_rgb method, accepts a color triplet or a list/array of color triplets. **Example**:: rgb = sc.hsv2rgb([0.23, 0.80, 0.74]) # Returns array([0.51504, 0.74 , 0.148 ]) """ colors, origndim = _listify_colors(colors) for c,color in enumerate(colors): hsvcolor = mpl.colors.hsv_to_rgb(color) colors[c] = hsvcolor colors = _listify_colors(colors, origndim) return colors
############################################################################## #%% Colormap-related functions ############################################################################## __all__ += ['vectocolor', 'arraycolors', 'gridcolors', 'midpointnorm', 'manualcolorbar', 'colormapdemo']
[docs] def vectocolor(vector, cmap=None, asarray=True, reverse=False, minval=None, maxval=None, midpoint=None, nancolor=None): """ This function converts a vector (i.e., 1D array) of N values into an Nx3 matrix of color values according to the current colormap. It automatically scales the vector to provide maximum dynamic range for the color map. Note: see sc.arraycolors() for multidimensional input. Args: vector (array): Input vector (or list, it's converted to an array) cmap (str): is the colormap (default: current) asarray (bool): whether to return as an array (otherwise, a list of tuples) reverse (bool): whether to reverse the list of colors minval (float): the minimum value to use maxval (float): the maximum value to use midpoint (float): the midpoint value to use nancolor (color): if supplied, use this color for NaN entries Returns: colors (array): Nx4 array of RGB-alpha color values **Example**:: n = 1000 x = np.random.randn(n,1); y = np.random.randn(n,1); c = sc.vectocolor(y); plt.scatter(x, y, c=c, s=50) | *New in version 1.2.0:* midpoint argument. | *New in version 2.1.0:* nancolor argument and remove nans by default | *New in version 3.0.0:* correct "midpoint" argument """ from numpy import array, zeros if cmap is None: cmap = plt.get_cmap() # Get current colormap elif isinstance(cmap, str): try: cmap = plt.get_cmap(cmap) except: # pragma: no cover choices = sc.newlinejoin(plt.colormaps()) raise ValueError(f'{cmap} is not a valid color map; choices are:\n{choices}') # If a scalar is supplied, convert it to a vector instead if sc.isnumber(vector): vector = np.linspace(0, 1, vector) # Usual situation -- the vector has elements vector = sc.dcp(vector) # To avoid in-place modification vector = np.array(vector, dtype=float) # Just to be sure if len(vector): if minval is None: minval = np.nanmin(vector) if maxval is None: maxval = np.nanmax(vector) diff = maxval - minval vector = (vector - minval)/diff # Normalize vector if midpoint is not None: vcenter = (midpoint - minval)/diff assert 0 <= vcenter <= 1, f'Values not in order: must be minval={minval:n} <= midpoint={midpoint:n} <= maxval={maxval:n}' norm = midpointnorm(vcenter=vcenter, vmin=0, vmax=1) vector = np.array(norm(vector)) nelements = len(vector) # Count number of elements colors = zeros((nelements,4)) for i in range(nelements): point = vector[i] if np.isnan(point) and nancolor is not None: color = sanitizecolor(nancolor, alpha=True) # If it's NaN else: color = array(cmap(point)) # Main use case colors[i,:] = color # It doesn't; just return black else: colors = (0,0,0,1) # Process output output = _processcolors(colors=colors, asarray=asarray, reverse=reverse) return output
[docs] def arraycolors(arr, **kwargs): """ Map an N-dimensional array of values onto the current colormap. An extension of vectocolor() for multidimensional arrays; see that function for additional arguments. Args: arr (array): a multidimensional array to be converted to an array of colors kwargs(dict): passed to :func:`sc.vectocolor() <vectocolor>` **Example**:: n = 1000 ncols = 5 arr = np.random.rand(n,ncols) for c in range(ncols): arr[:,c] += c x = np.random.rand(n) y = np.random.rand(n) colors = sc.arraycolors(arr) plt.figure(figsize=(20,16)) for c in range(ncols): plt.scatter(x+c, y, s=50, c=colors[:,c]) Version: 2020mar07 | *New in version 3.1.0:* Handle non-array output """ arr = sc.dcp(arr) # Avoid modifications new_shape = arr.shape + (4,) # RGBα colors = np.zeros(new_shape) colorvec = vectocolor(vector=arr.reshape(-1), **kwargs) if sc.isarray(colorvec): colors = colorvec.reshape(new_shape) else: errormsg = 'Creating array colors as a list does not make sense; use sc.vectocolor(arr.flatten()) if you mean to do this' raise ValueError(errormsg) return colors
[docs] def gridcolors(ncolors=10, limits=None, nsteps=20, asarray=False, ashex=False, reverse=False, hueshift=0, basis='default', demo=False): """ Create a qualitative "color map" by assigning points according to the maximum pairwise distance in the color cube. Basically, the algorithm generates n points that are maximally uniformly spaced in the [R, G, B] color cube. By default, if there are <=9 colors, use Colorbrewer colors; if there are 10-19 colors, use Kelly's colors; if there are >=20 colors, use uniformly spaced grid colors. Args: ncolors (int) : the number of colors to create limits (float) : how close to the edges of the cube to make colors (to avoid white and black) nsteps (int) : the discretization of the color cube (e.g. 10 = 10 units per side = 1000 points total) ashex (bool) : whether to return colors in hexadecimal representation asarray (bool) : whether to return the colors as an array instead of as a list of tuples reverse (bool) : whether to reverse the list of colors hueshift (float) : whether to shift the hue (hueshift > 0 and <=1) or not (0) demo (bool) : whether or not to plot the color cube itself basis (str) : what basis to use -- options are 'colorbrewer', 'kelly', 'default', or 'none' **Example**:: import numpy as np import matplotlib.pyplot as plt import sciris as sc ncolors = 10 piedata = np.random.rand(ncolors) colors = sc.gridcolors(ncolors) plt.pie(piedata, colors=colors) sc.gridcolors(ncolors, demo=True) plt.show() | *New in version 2018oct30.* | *New in version 3.2.0:* allow ncolors to be an iterable """ # Handle input arguments if not sc.isnumber(ncolors): if sc.isiterable(ncolors): ncolors = len(ncolors) else: errormsg = f'Invalid input {ncolors}; must be an integer or an iterable' raise TypeError(errormsg) # Choose default colors if basis == 'default': if ncolors<=9: basis = 'colorbrewer' # Use these cos they're nicer else: basis = 'kelly' # Use these cos there are more of them # Steal colorbrewer colors for small numbers of colors colorbrewercolors = np.array([ [ 55, 126, 184], # [27, 158, 119], # Old color [228, 26, 28], # [217, 95, 2], [ 77, 175, 74], # [117, 112, 179], [162, 78, 153], # [231, 41, 138], [255, 127, 0], [200, 200, 51], # Was too bright yellow [166, 86, 40], [247, 129, 191], [153, 153, 153], ])/255. # Steal Kelly's colors from https://gist.github.com/ollieglass/f6ddd781eeae1d24e391265432297538, removing # black: '222222', off-white: 'F2F3F4', mid-grey: '848482', kellycolors = ['F3C300', '875692', 'F38400', 'A1CAF1', 'BE0032', 'C2B280', '008856', 'E68FAC', '0067A5', 'F99379', '604E97', 'F6A600', 'B3446C', 'DCD300', '882D17', '8DB600', '654522', 'E25822', '2B3D26'] for c,color in enumerate(kellycolors): kellycolors[c] = list(hex2rgb(color)) kellycolors = np.array(kellycolors) if basis == 'colorbrewer' and ncolors<=len(colorbrewercolors): colors = colorbrewercolors[:ncolors] elif basis == 'kelly' and ncolors<=len(kellycolors): colors = kellycolors[:ncolors] else: # Too many colors, calculate instead ## Calculate sliding limits if none provided if limits is None: colorrange = 1-1/float(ncolors**0.5) limits = [0.5-colorrange/2, 0.5+colorrange/2] ## Calculate primitives and dot locations primitive = np.linspace(limits[0], limits[1], nsteps) # Define primitive color vector x, y, z = np.meshgrid(primitive, primitive, primitive) # Create grid of all possible points dots = np.transpose(np.array([x.flatten(), y.flatten(), z.flatten()])) # Flatten into an array of dots ndots = nsteps**3 # Calculate the number of dots ## Start from the colorbrewer colors if basis=='colorbrewer' or basis=='kelly': indices = [] # Initialize the array if basis == 'colorbrewer': basiscolors = colorbrewercolors elif basis == 'kelly': basiscolors = kellycolors for color in basiscolors: rgbdistances = dots - color # Calculate the distance in RGB space totaldistances = np.linalg.norm(rgbdistances,axis=1) closest = np.argmin(totaldistances) indices.append(closest) else: indices = [0] ## Calculate the distances for pt in range(ncolors-len(indices)): # Loop over each point totaldistances = np.inf+np.zeros(ndots) # Initialize distances for ind in indices: # Loop over each existing point rgbdistances = dots - dots[ind] # Calculate the distance in RGB space totaldistances = np.minimum(totaldistances, np.linalg.norm(rgbdistances,axis=1)) # Calculate the minimum Euclidean distance maxindex = np.argmax(totaldistances) # Find the point that maximizes the minimum distance indices.append(maxindex) # Append this index colors = dots[indices,:] ## Wrap up -- turn color array into a list, or reverse if hueshift: colors = shifthue(colors, hueshift=hueshift) # Shift hue if requested output = _processcolors(colors=colors, asarray=asarray, ashex=ashex, reverse=reverse) ## For plotting -- optional if demo: ax = sc.scatter3d(colors[:,0], colors[:,1], colors[:,2], c=output, s=200, depthshade=False, lw=0, fig=True, figkwargs={'facecolor':'w'}) ax.set_xlabel('Red', fontweight='bold') ax.set_ylabel('Green', fontweight='bold') ax.set_zlabel('Blue', fontweight='bold') ax.set_xlim((0,1)) ax.set_ylim((0,1)) ax.set_zlim((0,1)) return output
[docs] def midpointnorm(vcenter=0, vmin=None, vmax=None): """ Alias to Matplotlib's TwoSlopeNorm. Used to place the center of the colormap somewhere other than the center of the data. Args: vcenter (float): the center of the colormap (0 by default) vmin (float): the minimum of the colormap vmax (float): the maximum of the colormap **Example**:: data = np.random.rand(10,10) - 0.2 plt.pcolor(data, cmap='bi', norm=sc.midpointnorm()) | *New in version 1.2.0.* """ norm = mpl.colors.TwoSlopeNorm(vcenter=vcenter, vmin=vmin, vmax=vmax) return norm
[docs] def manualcolorbar(data=None, vmin=0, vmax=1, vcenter=None, colors=None, values=None, cmap=None, norm=None, label=None, labelkwargs=None, ticks=None, ticklabels=None, fig=None, ax=None, cax=None, axkwargs=None, **kwargs): """ Add a colorbar to a plot that does not support one by default. There are three main use cases, from least to most manual: - The most common use case is to supply the data used for plotting directly via ``data``; the function will the infer the lower and upper limits and construct the colorbar. - Alternatively, the lower and upper limits can be provided manually via ``vmin`` and ``vmax``. - Finally, the colors themselves can be provided via ``colors``, optionally mapped to ``values``, and potentially also supplied with custom ``ticklabels``. Args: data (arr): if provided, compute the colorbar from these data vmin (float): the minimum of the colormap (optional if data are provided) vmax (float): the maximum of the colormap (optional if data are provided) vcenter (float): the center of the colormap (optional) colors (arr): if provided, use these colors directly instead values (arr): if provided, the values corresponding to the specific colors cmap (str/arr): the colormap to use norm (Norm): the Matplotlib norm to use (if not provided, use the midpoint norm with vmin, vmax, etc.) label (str): the label for the colorbar labelkwargs (dict): passed to the colorbar label ticks (list): the tick locations to use for the colorbar ticklabels (list): the tick labels to use ax (Axes): the "parent" axes to associate the colorbar with cax (Axes): the axes to draw the colorbar into axkwargs (dict): if creating a new colorbar axes, the arguments for creating it kwargs (dict): passed to :func:`matplotlib.colorbar.ColorbarBase` **Examples**:: # Create a default colorbar sc.manualcolorbar() # Add a colorbar to non-mappable data (e.g. a scatterplot) n = 1000 x = np.random.randn(n) y = np.random.randn(n) c = x**2 + y**2 plt.scatter(x, y, c=c) sc.manualcolorbar(c) # Create a custom colorbar with a custom label sc.manualcolorbar( vmin=-20, vmax=40, vcenter=0, cmap='orangeblue', label='Cold/hot', orientation='horizontal', labelkwargs=dict(rotation=10, fontweight='bold'), axkwargs=[0.1,0.5,0.8,0.1], ) # Create a completely custom colorbar n = 12 x = np.arange(n) values = np.sqrt(np.arange(n)) colors = sc.gridcolors(n) plt.scatter(x, values, c=colors) plt.grid(True) ticklabels = ['' for i in range(n)] for i in [0, 2, 4, 10, 11]: ticklabels[i] = f'Color {i} is nice' cb = sc.manualcolorbar( colors=colors, values=values, ticks=values, ticklabels=ticklabels, spacing='proportional' ) | *New in version 3.1.0.* """ labelkwargs = sc.mergedicts(labelkwargs) # Get the colorbar axes if sc.checktype(axkwargs, 'arraylike'): axarg = axkwargs axkwargs = {} else: axarg = None axkwargs = sc.mergedicts(axkwargs) if cax is None and (axarg or axkwargs): cax = plt.axes(arg=axarg, **axkwargs) if ax is None and cax is None: ax = plt.gca() # We need an axis or colorbar axis # Handle explicit colors if colors is not None: if values is None: # Generate the boundaries automatically values = np.arange(len(colors)+1) if len(values) == len(colors): # Add an upper bound if not provided values = sc.cat(values, values[-1] + np.diff(values[-2:])) # Add the last diff on again cmap = mpl.colors.ListedColormap(colors) norm = mpl.colors.BoundaryNorm(values, cmap.N) sm = mpl.cm.ScalarMappable(cmap=cmap, norm=norm) # Main use case: infer colors else: # If data is provided, use that to get the minimum and maximum if data is not None: data = np.array(data) vmin = data.min() vmax = data.max() # Handle the center if vcenter is None: vcenter = (vmin + vmax) / 2 # Handle a custom norm if norm is None: norm = midpointnorm(vcenter=vcenter, vmin=vmin, vmax=vmax) # Create the scalar mappable sm = mpl.cm.ScalarMappable(norm=norm, cmap=cmap) # Create the colorbar cb = plt.colorbar(sm, ax=ax, cax=cax, ticks=ticks, **kwargs) if label: cb.set_label(label, **labelkwargs) if ticklabels: if cb.orientation == 'vertical': cb.ax.set_yticklabels(ticklabels) else: cb.ax.set_xticklabels(ticklabels) return cb
[docs] def colormapdemo(cmap=None, n=None, smoothing=None, randseed=None, doshow=True): """ Demonstrate a color map using simulated elevation data, shown in both 2D and 3D. The argument can be either a colormap itself or a string describing a colormap. **Examples**:: sc.colormapdemo('inferno') # Use a registered Matplotlib colormap sc.colormapdemo('parula') # Use a registered Sciris colormap sc.colormapdemo(sc.alpinecolormap(), n=200, smoothing=20, randseed=2942) # Use a colormap object Version: 2019aug22 """ # Set data if n is None: n = 100 if smoothing is None: smoothing = 40 if randseed is None: randseed = 8 if cmap is None: cmap = 'parula' # For no particular reason maxheight = 1 horizontalsize = 4 np.random.seed(randseed) kernel = np.array([0.25,0.5,0.25]) data = np.random.randn(n,n) for s in range(smoothing): # Quick-and-dirty-and-slow smoothing for i in range(n): data[:,i] = np.convolve(data[:,i],kernel,mode='same') for i in range(n): data[i,:] = np.convolve(data[i,:],kernel,mode='same') data -= data.min() data /= data.max() data *= maxheight # Plot in 2D fig1 = plt.figure(figsize=(10,8)) X = np.linspace(0,horizontalsize,n) pcl = plt.pcolor(X, X, data, cmap=cmap, linewidth=0, antialiased=False, shading='auto') cb2 = fig1.colorbar(pcl) cb2.set_label('Height (km)',horizontalalignment='right', labelpad=50) plt.xlabel('Position (km)') plt.ylabel('Position (km)') if doshow: # pragma: no cover plt.show() # Plot in 3D fig2,ax2 = sc.fig3d(returnax=True, figsize=(12,8)) ax2.view_init(elev=45, azim=30) X = np.linspace(0,horizontalsize,n) X, Y = np.meshgrid(X, X) surf = ax2.plot_surface(X, Y, data, rstride=1, cstride=1, cmap=cmap, linewidth=0, antialiased=False) cb = fig2.colorbar(surf) cb.set_label('Height (km)', horizontalalignment='right', labelpad=50) plt.xlabel('Position (km)') plt.ylabel('Position (km)') if doshow: # pragma: no cover plt.show() return {'2d':fig1, '3d':fig2}
############################################################################## #%% Colormaps ############################################################################## __all__ += ['alpinecolormap', 'bicolormap', 'parulacolormap', 'turbocolormap', 'bandedcolormap', 'orangebluecolormap']
[docs] def alpinecolormap(apply=False): """ This function generates a map based on ascending height. Based on data from Kazakhstan. **Test case**:: sc.colormapdemo('alpine') **Usage example**:: import sciris as sc import matplotlib.pyplot as plt plt.imshow(np.random.randn(20,20), interpolation='none', cmap=sc.alpinecolormap()) Version: 2014aug06 """ # Set parameters water = np.array([3,18,59])/256. desert = np.array([194,175,160*0.6])/256. forest1 = np.array([61,86,46])/256. forest2 = np.array([61,86,46])/256.*1.2 rock = np.array([119,111,109])/256.*1.3 snow = np.array([243,239,238])/256. breaks = [0.0,0.5,0.7,0.8,0.9,1.0] # Create dictionary cdict = {'red': ((breaks[0], water[0], water[0]), (breaks[1], desert[0], desert[0]), (breaks[2], forest1[0], forest1[0]), (breaks[3], forest2[0], forest2[0]), (breaks[4], rock[0], rock[0]), (breaks[5], snow[0], snow[0])), 'green': ((breaks[0], water[1], water[1]), (breaks[1], desert[1], desert[1]), (breaks[2], forest1[1], forest1[1]), (breaks[3], forest2[1], forest2[1]), (breaks[4], rock[1], rock[1]), (breaks[5], snow[1], snow[1])), 'blue': ((breaks[0], water[2], water[2]), (breaks[1], desert[2], desert[2]), (breaks[2], forest1[2], forest1[2]), (breaks[3], forest2[2], forest2[2]), (breaks[4], rock[2], rock[2]), (breaks[5], snow[2], snow[2]))} # Make map cmap = mpl.colors.LinearSegmentedColormap('alpine', cdict, 256) if apply: # pragma: no cover plt.set_cmap(cmap) return cmap
[docs] def bicolormap(gap=0.1, mingreen=0.2, redbluemix=0.5, epsilon=0.01, demo=False, apply=False): """ This function generators a two-color map, blue for negative, red for positive changes, with grey in the middle. The input argument is how much of a color gap there is between the red scale and the blue one. Args: gap (float): sets how big of a gap between red and blue color scales there is (0=no gap; 1=pure red and pure blue) mingreen (float): how much green to include at the extremes of the red-blue color scale redbluemix (float): how much red to mix with the blue and vice versa at the extremes of the scale epsilon (float): what fraction of the colormap to make gray in the middle demo (bool): whether to plot a demo bicolormap or not apply (bool): whether to apply this colormap to the current figure **Examples**:: sc.bicolormap(gap=0, mingreen=0, redbluemix=1, epsilon=0) # From pure red to pure blue with white in the middle sc.bicolormap(gap=0, mingreen=0, redbluemix=0, epsilon=0.1) # Red -> yellow -> gray -> turquoise -> blue sc.bicolormap(gap=0.3, mingreen=0.2, redbluemix=0, epsilon=0.01) # Red and blue with a sharp distinction between Version: 2013sep13 """ mng = mingreen # Minimum amount of green to add into the colors mix = redbluemix # How much red to mix with the blue an vice versa eps = epsilon # How much of the center of the colormap to make gray omg = 1-gap # omg = one minus gap cdict = {'red': ((0.00000, 0.0, 0.0), (0.5-eps, mix, omg), (0.50000, omg, omg), (0.5+eps, omg, 1.0), (1.00000, 1.0, 1.0)), 'green': ((0.00000, mng, mng), (0.5-eps, omg, omg), (0.50000, omg, omg), (0.5+eps, omg, omg), (1.00000, mng, mng)), 'blue': ((0.00000, 1.0, 1.0), (0.5-eps, 1.0, omg), (0.50000, omg, omg), (0.5+eps, omg, mix), (1.00000, 0.0, 0.0))} cmap = mpl.colors.LinearSegmentedColormap('bi', cdict, 256) if apply: # pragma: no cover plt.set_cmap(cmap) def demoplot(): # pragma: no cover maps = [] maps.append(bicolormap()) # Default ,should work for most things maps.append(bicolormap(gap=0,mingreen=0,redbluemix=1,epsilon=0)) # From pure red to pure blue with white in the middle maps.append(bicolormap(gap=0,mingreen=0,redbluemix=0,epsilon=0.1)) # Red -> yellow -> gray -> turquoise -> blue maps.append(bicolormap(gap=0.3,mingreen=0.2,redbluemix=0,epsilon=0.01)) # Red and blue with a sharp distinction between nexamples=len(maps) plt.figure(figsize=(5*nexamples, 4)) for m in range(nexamples): plt.subplot(1, nexamples, m+1) plt.imshow(np.random.rand(20,20), cmap=maps[m], interpolation='none') plt.colorbar() plt.show() if demo: # pragma: no cover demoplot() return cmap
[docs] def parulacolormap(apply=False): """ Create a map similar to Viridis, but brighter. Set apply=True to use immediately. **Demo and example**:: cmap = sc.parulacolormap() sc.colormapdemo(cmap=cmap) Version: 2019aug22 """ data = [[0.2422,0.1504,0.6603], [0.2444,0.1534,0.6728], [0.2464,0.1569,0.6847], [0.2484,0.1607,0.6961], [0.2503,0.1648,0.7071], [0.2522,0.1689,0.7179], [0.2540,0.1732,0.7286], [0.2558,0.1773,0.7393], [0.2576,0.1814,0.7501], [0.2594,0.1854,0.7610], [0.2611,0.1893,0.7719], [0.2628,0.1932,0.7828], [0.2645,0.1972,0.7937], [0.2661,0.2011,0.8043], [0.2676,0.2052,0.8148], [0.2691,0.2094,0.8249], [0.2704,0.2138,0.8346], [0.2717,0.2184,0.8439], [0.2729,0.2231,0.8528], [0.2740,0.2280,0.8612], [0.2749,0.2330,0.8692], [0.2758,0.2382,0.8767], [0.2766,0.2435,0.8840], [0.2774,0.2489,0.8908], [0.2781,0.2543,0.8973], [0.2788,0.2598,0.9035], [0.2794,0.2653,0.9094], [0.2798,0.2708,0.9150], [0.2802,0.2764,0.9204], [0.2806,0.2819,0.9255], [0.2809,0.2875,0.9305], [0.2811,0.2930,0.9352], [0.2813,0.2985,0.9397], [0.2814,0.3040,0.9441], [0.2814,0.3095,0.9483], [0.2813,0.3150,0.9524], [0.2811,0.3204,0.9563], [0.2809,0.3259,0.9600], [0.2807,0.3313,0.9636], [0.2803,0.3367,0.9670], [0.2798,0.3421,0.9702], [0.2791,0.3475,0.9733], [0.2784,0.3529,0.9763], [0.2776,0.3583,0.9791], [0.2766,0.3638,0.9817], [0.2754,0.3693,0.9840], [0.2741,0.3748,0.9862], [0.2726,0.3804,0.9881], [0.2710,0.3860,0.9898], [0.2691,0.3916,0.9912], [0.2670,0.3973,0.9924], [0.2647,0.4030,0.9935], [0.2621,0.4088,0.9946], [0.2591,0.4145,0.9955], [0.2556,0.4203,0.9965], [0.2517,0.4261,0.9974], [0.2473,0.4319,0.9983], [0.2424,0.4378,0.9991], [0.2369,0.4437,0.9996], [0.2311,0.4497,0.9995], [0.2250,0.4559,0.9985], [0.2189,0.4620,0.9968], [0.2128,0.4682,0.9948], [0.2066,0.4743,0.9926], [0.2006,0.4803,0.9906], [0.1950,0.4861,0.9887], [0.1903,0.4919,0.9867], [0.1869,0.4975,0.9844], [0.1847,0.5030,0.9819], [0.1831,0.5084,0.9793], [0.1818,0.5138,0.9766], [0.1806,0.5191,0.9738], [0.1795,0.5244,0.9709], [0.1785,0.5296,0.9677], [0.1778,0.5349,0.9641], [0.1773,0.5401,0.9602], [0.1768,0.5452,0.9560], [0.1764,0.5504,0.9516], [0.1755,0.5554,0.9473], [0.1740,0.5605,0.9432], [0.1716,0.5655,0.9393], [0.1686,0.5705,0.9357], [0.1649,0.5755,0.9323], [0.1610,0.5805,0.9289], [0.1573,0.5854,0.9254], [0.1540,0.5902,0.9218], [0.1513,0.5950,0.9182], [0.1492,0.5997,0.9147], [0.1475,0.6043,0.9113], [0.1461,0.6089,0.9080], [0.1446,0.6135,0.9050], [0.1429,0.6180,0.9022], [0.1408,0.6226,0.8998], [0.1383,0.6272,0.8975], [0.1354,0.6317,0.8953], [0.1321,0.6363,0.8932], [0.1288,0.6408,0.8910], [0.1253,0.6453,0.8887], [0.1219,0.6497,0.8862], [0.1185,0.6541,0.8834], [0.1152,0.6584,0.8804], [0.1119,0.6627,0.8770], [0.1085,0.6669,0.8734], [0.1048,0.6710,0.8695], [0.1009,0.6750,0.8653], [0.0964,0.6789,0.8609], [0.0914,0.6828,0.8562], [0.0855,0.6865,0.8513], [0.0789,0.6902,0.8462], [0.0713,0.6938,0.8409], [0.0628,0.6972,0.8355], [0.0535,0.7006,0.8299], [0.0433,0.7039,0.8242], [0.0328,0.7071,0.8183], [0.0234,0.7103,0.8124], [0.0155,0.7133,0.8064], [0.0091,0.7163,0.8003], [0.0046,0.7192,0.7941], [0.0019,0.7220,0.7878], [0.0009,0.7248,0.7815], [0.0018,0.7275,0.7752], [0.0046,0.7301,0.7688], [0.0094,0.7327,0.7623], [0.0162,0.7352,0.7558], [0.0253,0.7376,0.7492], [0.0369,0.7400,0.7426], [0.0504,0.7423,0.7359], [0.0638,0.7446,0.7292], [0.0770,0.7468,0.7224], [0.0899,0.7489,0.7156], [0.1023,0.7510,0.7088], [0.1141,0.7531,0.7019], [0.1252,0.7552,0.6950], [0.1354,0.7572,0.6881], [0.1448,0.7593,0.6812], [0.1532,0.7614,0.6741], [0.1609,0.7635,0.6671], [0.1678,0.7656,0.6599], [0.1741,0.7678,0.6527], [0.1799,0.7699,0.6454], [0.1853,0.7721,0.6379], [0.1905,0.7743,0.6303], [0.1954,0.7765,0.6225], [0.2003,0.7787,0.6146], [0.2061,0.7808,0.6065], [0.2118,0.7828,0.5983], [0.2178,0.7849,0.5899], [0.2244,0.7869,0.5813], [0.2318,0.7887,0.5725], [0.2401,0.7905,0.5636], [0.2491,0.7922,0.5546], [0.2589,0.7937,0.5454], [0.2695,0.7951,0.5360], [0.2809,0.7964,0.5266], [0.2929,0.7975,0.5170], [0.3052,0.7985,0.5074], [0.3176,0.7994,0.4975], [0.3301,0.8002,0.4876], [0.3424,0.8009,0.4774], [0.3548,0.8016,0.4669], [0.3671,0.8021,0.4563], [0.3795,0.8026,0.4454], [0.3921,0.8029,0.4344], [0.4050,0.8031,0.4233], [0.4184,0.8030,0.4122], [0.4322,0.8028,0.4013], [0.4463,0.8024,0.3904], [0.4608,0.8018,0.3797], [0.4753,0.8011,0.3691], [0.4899,0.8002,0.3586], [0.5044,0.7993,0.3480], [0.5187,0.7982,0.3374], [0.5329,0.7970,0.3267], [0.5470,0.7957,0.3159], [0.5609,0.7943,0.3050], [0.5748,0.7929,0.2941], [0.5886,0.7913,0.2833], [0.6024,0.7896,0.2726], [0.6161,0.7878,0.2622], [0.6297,0.7859,0.2521], [0.6433,0.7839,0.2423], [0.6567,0.7818,0.2329], [0.6701,0.7796,0.2239], [0.6833,0.7773,0.2155], [0.6963,0.7750,0.2075], [0.7091,0.7727,0.1998], [0.7218,0.7703,0.1924], [0.7344,0.7679,0.1852], [0.7468,0.7654,0.1782], [0.7590,0.7629,0.1717], [0.7710,0.7604,0.1658], [0.7829,0.7579,0.1608], [0.7945,0.7554,0.1570], [0.8060,0.7529,0.1546], [0.8172,0.7505,0.1535], [0.8281,0.7481,0.1536], [0.8389,0.7457,0.1546], [0.8495,0.7435,0.1564], [0.8600,0.7413,0.1587], [0.8703,0.7392,0.1615], [0.8804,0.7372,0.1650], [0.8903,0.7353,0.1695], [0.9000,0.7336,0.1749], [0.9093,0.7321,0.1815], [0.9184,0.7308,0.1890], [0.9272,0.7298,0.1973], [0.9357,0.7290,0.2061], [0.9440,0.7285,0.2151], [0.9523,0.7284,0.2237], [0.9606,0.7285,0.2312], [0.9689,0.7292,0.2373], [0.9770,0.7304,0.2418], [0.9842,0.7330,0.2446], [0.9900,0.7365,0.2429], [0.9946,0.7407,0.2394], [0.9966,0.7458,0.2351], [0.9971,0.7513,0.2309], [0.9972,0.7569,0.2267], [0.9971,0.7626,0.2224], [0.9969,0.7683,0.2181], [0.9966,0.7740,0.2138], [0.9962,0.7798,0.2095], [0.9957,0.7856,0.2053], [0.9949,0.7915,0.2012], [0.9938,0.7974,0.1974], [0.9923,0.8034,0.1939], [0.9906,0.8095,0.1906], [0.9885,0.8156,0.1875], [0.9861,0.8218,0.1846], [0.9835,0.8280,0.1817], [0.9807,0.8342,0.1787], [0.9778,0.8404,0.1757], [0.9748,0.8467,0.1726], [0.9720,0.8529,0.1695], [0.9694,0.8591,0.1665], [0.9671,0.8654,0.1636], [0.9651,0.8716,0.1608], [0.9634,0.8778,0.1582], [0.9619,0.8840,0.1557], [0.9608,0.8902,0.1532], [0.9601,0.8963,0.1507], [0.9596,0.9023,0.1480], [0.9595,0.9084,0.1450], [0.9597,0.9143,0.1418], [0.9601,0.9203,0.1382], [0.9608,0.9262,0.1344], [0.9618,0.9320,0.1304], [0.9629,0.9379,0.1261], [0.9642,0.9437,0.1216], [0.9657,0.9494,0.1168], [0.9674,0.9552,0.1116], [0.9692,0.9609,0.1061], [0.9711,0.9667,0.1001], [0.9730,0.9724,0.0938], [0.9749,0.9782,0.0872], [0.9769,0.9839,0.0805]] cmap = mpl.colors.LinearSegmentedColormap.from_list('parula', data) if apply: # pragma: no cover plt.set_cmap(cmap) return cmap
[docs] def turbocolormap(apply=False): """ NOTE: as of Matplotlib 3.4.0, this colormap is included by default, and will soon be removed from Sciris. Copyright 2019 Google LLC. SPDX-License-Identifier: Apache-2.0 Author: Anton Mikhailov Borrowed directly from https://gist.github.com/mikhailov-work/ee72ba4191942acecc03fe6da94fc73f, with thanks! Create a map similar to Jet, but better. Set apply=True to use immediately. **Demo and example**:: cmap = sc.turbocolormap() sc.colormapdemo(cmap=cmap) Version: 2020mar20 """ data = [[0.18995,0.07176,0.23217],[0.19483,0.08339,0.26149],[0.19956,0.09498,0.29024],[0.20415,0.10652,0.31844],[0.20860,0.11802,0.34607],[0.21291,0.12947,0.37314],[0.21708,0.14087,0.39964],[0.22111,0.15223,0.42558], [0.22500,0.16354,0.45096],[0.22875,0.17481,0.47578],[0.23236,0.18603,0.50004],[0.23582,0.19720,0.52373],[0.23915,0.20833,0.54686],[0.24234,0.21941,0.56942],[0.24539,0.23044,0.59142],[0.24830,0.24143,0.61286], [0.25107,0.25237,0.63374],[0.25369,0.26327,0.65406],[0.25618,0.27412,0.67381],[0.25853,0.28492,0.69300],[0.26074,0.29568,0.71162],[0.26280,0.30639,0.72968],[0.26473,0.31706,0.74718],[0.26652,0.32768,0.76412], [0.26816,0.33825,0.78050],[0.26967,0.34878,0.79631],[0.27103,0.35926,0.81156],[0.27226,0.36970,0.82624],[0.27334,0.38008,0.84037],[0.27429,0.39043,0.85393],[0.27509,0.40072,0.86692],[0.27576,0.41097,0.87936], [0.27628,0.42118,0.89123],[0.27667,0.43134,0.90254],[0.27691,0.44145,0.91328],[0.27701,0.45152,0.92347],[0.27698,0.46153,0.93309],[0.27680,0.47151,0.94214],[0.27648,0.48144,0.95064],[0.27603,0.49132,0.95857], [0.27543,0.50115,0.96594],[0.27469,0.51094,0.97275],[0.27381,0.52069,0.97899],[0.27273,0.53040,0.98461],[0.27106,0.54015,0.98930],[0.26878,0.54995,0.99303],[0.26592,0.55979,0.99583],[0.26252,0.56967,0.99773], [0.25862,0.57958,0.99876],[0.25425,0.58950,0.99896],[0.24946,0.59943,0.99835],[0.24427,0.60937,0.99697],[0.23874,0.61931,0.99485],[0.23288,0.62923,0.99202],[0.22676,0.63913,0.98851],[0.22039,0.64901,0.98436], [0.21382,0.65886,0.97959],[0.20708,0.66866,0.97423],[0.20021,0.67842,0.96833],[0.19326,0.68812,0.96190],[0.18625,0.69775,0.95498],[0.17923,0.70732,0.94761],[0.17223,0.71680,0.93981],[0.16529,0.72620,0.93161], [0.15844,0.73551,0.92305],[0.15173,0.74472,0.91416],[0.14519,0.75381,0.90496],[0.13886,0.76279,0.89550],[0.13278,0.77165,0.88580],[0.12698,0.78037,0.87590],[0.12151,0.78896,0.86581],[0.11639,0.79740,0.85559], [0.11167,0.80569,0.84525],[0.10738,0.81381,0.83484],[0.10357,0.82177,0.82437],[0.10026,0.82955,0.81389],[0.09750,0.83714,0.80342],[0.09532,0.84455,0.79299],[0.09377,0.85175,0.78264],[0.09287,0.85875,0.77240], [0.09267,0.86554,0.76230],[0.09320,0.87211,0.75237],[0.09451,0.87844,0.74265],[0.09662,0.88454,0.73316],[0.09958,0.89040,0.72393],[0.10342,0.89600,0.71500],[0.10815,0.90142,0.70599],[0.11374,0.90673,0.69651], [0.12014,0.91193,0.68660],[0.12733,0.91701,0.67627],[0.13526,0.92197,0.66556],[0.14391,0.92680,0.65448],[0.15323,0.93151,0.64308],[0.16319,0.93609,0.63137],[0.17377,0.94053,0.61938],[0.18491,0.94484,0.60713], [0.19659,0.94901,0.59466],[0.20877,0.95304,0.58199],[0.22142,0.95692,0.56914],[0.23449,0.96065,0.55614],[0.24797,0.96423,0.54303],[0.26180,0.96765,0.52981],[0.27597,0.97092,0.51653],[0.29042,0.97403,0.50321], [0.30513,0.97697,0.48987],[0.32006,0.97974,0.47654],[0.33517,0.98234,0.46325],[0.35043,0.98477,0.45002],[0.36581,0.98702,0.43688],[0.38127,0.98909,0.42386],[0.39678,0.99098,0.41098],[0.41229,0.99268,0.39826], [0.42778,0.99419,0.38575],[0.44321,0.99551,0.37345],[0.45854,0.99663,0.36140],[0.47375,0.99755,0.34963],[0.48879,0.99828,0.33816],[0.50362,0.99879,0.32701],[0.51822,0.99910,0.31622],[0.53255,0.99919,0.30581], [0.54658,0.99907,0.29581],[0.56026,0.99873,0.28623],[0.57357,0.99817,0.27712],[0.58646,0.99739,0.26849],[0.59891,0.99638,0.26038],[0.61088,0.99514,0.25280],[0.62233,0.99366,0.24579],[0.63323,0.99195,0.23937], [0.64362,0.98999,0.23356],[0.65394,0.98775,0.22835],[0.66428,0.98524,0.22370],[0.67462,0.98246,0.21960],[0.68494,0.97941,0.21602],[0.69525,0.97610,0.21294],[0.70553,0.97255,0.21032],[0.71577,0.96875,0.20815], [0.72596,0.96470,0.20640],[0.73610,0.96043,0.20504],[0.74617,0.95593,0.20406],[0.75617,0.95121,0.20343],[0.76608,0.94627,0.20311],[0.77591,0.94113,0.20310],[0.78563,0.93579,0.20336],[0.79524,0.93025,0.20386], [0.80473,0.92452,0.20459],[0.81410,0.91861,0.20552],[0.82333,0.91253,0.20663],[0.83241,0.90627,0.20788],[0.84133,0.89986,0.20926],[0.85010,0.89328,0.21074],[0.85868,0.88655,0.21230],[0.86709,0.87968,0.21391], [0.87530,0.87267,0.21555],[0.88331,0.86553,0.21719],[0.89112,0.85826,0.21880],[0.89870,0.85087,0.22038],[0.90605,0.84337,0.22188],[0.91317,0.83576,0.22328],[0.92004,0.82806,0.22456],[0.92666,0.82025,0.22570], [0.93301,0.81236,0.22667],[0.93909,0.80439,0.22744],[0.94489,0.79634,0.22800],[0.95039,0.78823,0.22831],[0.95560,0.78005,0.22836],[0.96049,0.77181,0.22811],[0.96507,0.76352,0.22754],[0.96931,0.75519,0.22663], [0.97323,0.74682,0.22536],[0.97679,0.73842,0.22369],[0.98000,0.73000,0.22161],[0.98289,0.72140,0.21918],[0.98549,0.71250,0.21650],[0.98781,0.70330,0.21358],[0.98986,0.69382,0.21043],[0.99163,0.68408,0.20706], [0.99314,0.67408,0.20348],[0.99438,0.66386,0.19971],[0.99535,0.65341,0.19577],[0.99607,0.64277,0.19165],[0.99654,0.63193,0.18738],[0.99675,0.62093,0.18297],[0.99672,0.60977,0.17842],[0.99644,0.59846,0.17376], [0.99593,0.58703,0.16899],[0.99517,0.57549,0.16412],[0.99419,0.56386,0.15918],[0.99297,0.55214,0.15417],[0.99153,0.54036,0.14910],[0.98987,0.52854,0.14398],[0.98799,0.51667,0.13883],[0.98590,0.50479,0.13367], [0.98360,0.49291,0.12849],[0.98108,0.48104,0.12332],[0.97837,0.46920,0.11817],[0.97545,0.45740,0.11305],[0.97234,0.44565,0.10797],[0.96904,0.43399,0.10294],[0.96555,0.42241,0.09798],[0.96187,0.41093,0.09310], [0.95801,0.39958,0.08831],[0.95398,0.38836,0.08362],[0.94977,0.37729,0.07905],[0.94538,0.36638,0.07461],[0.94084,0.35566,0.07031],[0.93612,0.34513,0.06616],[0.93125,0.33482,0.06218],[0.92623,0.32473,0.05837], [0.92105,0.31489,0.05475],[0.91572,0.30530,0.05134],[0.91024,0.29599,0.04814],[0.90463,0.28696,0.04516],[0.89888,0.27824,0.04243],[0.89298,0.26981,0.03993],[0.88691,0.26152,0.03753],[0.88066,0.25334,0.03521], [0.87422,0.24526,0.03297],[0.86760,0.23730,0.03082],[0.86079,0.22945,0.02875],[0.85380,0.22170,0.02677],[0.84662,0.21407,0.02487],[0.83926,0.20654,0.02305],[0.83172,0.19912,0.02131],[0.82399,0.19182,0.01966], [0.81608,0.18462,0.01809],[0.80799,0.17753,0.01660],[0.79971,0.17055,0.01520],[0.79125,0.16368,0.01387],[0.78260,0.15693,0.01264],[0.77377,0.15028,0.01148],[0.76476,0.14374,0.01041],[0.75556,0.13731,0.00942], [0.74617,0.13098,0.00851],[0.73661,0.12477,0.00769],[0.72686,0.11867,0.00695],[0.71692,0.11268,0.00629],[0.70680,0.10680,0.00571],[0.69650,0.10102,0.00522],[0.68602,0.09536,0.00481],[0.67535,0.08980,0.00449], [0.66449,0.08436,0.00424],[0.65345,0.07902,0.00408],[0.64223,0.07380,0.00401],[0.63082,0.06868,0.00401],[0.61923,0.06367,0.00410],[0.60746,0.05878,0.00427],[0.59550,0.05399,0.00453],[0.58336,0.04931,0.00486], [0.57103,0.04474,0.00529],[0.55852,0.04028,0.00579],[0.54583,0.03593,0.00638],[0.53295,0.03169,0.00705],[0.51989,0.02756,0.00780],[0.50664,0.02354,0.00863],[0.49321,0.01963,0.00955],[0.47960,0.01583,0.01055]] cmap = mpl.colors.LinearSegmentedColormap.from_list('turbo', data) if apply: # pragma: no cover plt.set_cmap(cmap) return cmap
[docs] def bandedcolormap(minvalue=None, minsaturation=None, hueshift=None, saturationscale=None, npts=None, apply=False): """ Map colors onto bands of hue and saturation, with lightness mapped linearly. Unlike most colormaps, this colormap does not aim to be percentually uniform, but rather aims to make it easy to relate colors to as-exact-as-possible numbers (while still maintaining a semblance of overall trend from low to high). **Demo and example**:: cmap = sc.bandedcolormap(minvalue=0, minsaturation=0) sc.colormapdemo(cmap=cmap) Version: 2019aug22 """ # Set parameters if minvalue is None: minvalue = 0.1 if hueshift is None: hueshift = 0.8 if minsaturation is None: minsaturation = 0.5 if saturationscale is None: saturationscale = 4.3 if npts is None: npts = 256 # Calculate x = np.linspace(0, np.pi, npts) hsv = np.zeros((npts, 3)) hsv[:,2] = np.sqrt(np.linspace(minvalue,1,npts)) # Value: map linearly hsv[:,0] = np.sin(x+hueshift)**2 # Hue: a big sine wave hsv[:,1] = minsaturation+(1-minsaturation)*np.sin(saturationscale*x)**2 # Saturation: a small sine wave data = hsv2rgb(hsv) # Create and use cmap = mpl.colors.LinearSegmentedColormap.from_list('banded', data) if apply: # pragma: no cover plt.set_cmap(cmap) return cmap
[docs] def orangebluecolormap(apply=False): """ Create an orange-blue colormap; most like RdYlBu but more pleasing. Created by Prashanth Selvaraj. **Demo and example**:: cmap = sc.orangebluecolormap() sc.colormapdemo(cmap=cmap) | *New in version 1.0.0.* """ bottom = plt.get_cmap('Oranges', 128) top = plt.get_cmap('Blues_r', 128) x = np.linspace(0, 1, 128) data = np.vstack((top(x), bottom(x))) # Create and use cmap = mpl.colors.LinearSegmentedColormap.from_list('orangeblue', data) if apply: # pragma: no cover plt.set_cmap(cmap) return cmap
# Register colormaps -- under their original names as well as with the "sciris-" prefix try: # Regression support for Matplotlib register_func = mpl.colormaps.register # Matplotlib >=3.5 except AttributeError: register_func = mpl.cm.register_cmap # Matplotlib <=3.4 existing = plt.colormaps() colormap_map = dict( alpine = alpinecolormap(), parula = parulacolormap(), banded = bandedcolormap(), bi = bicolormap(), orangeblue = orangebluecolormap(), turbo = turbocolormap(), ) for basename,cmap in colormap_map.items(): sc_name = f'sciris-{basename}' for name in [basename, sc_name]: if name not in existing: # Avoid re-registering already registered colormaps register_func(cmap=cmap, name=name)