Source code for cufflinks.colors

##
# Special thanks to @krey for the python3 support
##

import numpy as np
import colorsys
import colorlover as cl
import operator
import copy

from collections import deque
from six import string_types
from IPython.display import HTML, display

from . import themes
from .utils import inverseDict
from .auth import get_config_file


[docs]class CufflinksError(Exception): pass
[docs]def to_rgba(color, alpha): """ Converts from hex|rgb to rgba Parameters: ----------- color : string Color representation on hex or rgb alpha : float Value from 0 to 1.0 that represents the alpha value. Example: to_rgba('#E1E5ED',0.6) to_rgba('#f03',0.7) to_rgba('rgb(23,23,23)',.5) """ if type(color) == tuple: color, alpha = color color = color.lower() if 'rgba' in color: cl = list(eval(color.replace('rgba', ''))) if alpha: cl[3] = alpha return 'rgba' + str(tuple(cl)) elif 'rgb' in color: r, g, b = eval(color.replace('rgb', '')) return 'rgba' + str((r, g, b, alpha)) else: return to_rgba(hex_to_rgb(color), alpha)
[docs]def hex_to_rgb(color): """ Converts from hex to rgb Parameters: ----------- color : string Color representation on hex or rgb Example: hex_to_rgb('#E1E5ED') hex_to_rgb('#f03') """ color = normalize(color) color = color[1:] # return 'rgb'+str(tuple(ord(c) for c in color.decode('hex'))) return 'rgb' + str((int(color[0:2], base=16), int(color[2:4], base=16), int(color[4:6], base=16)))
[docs]def normalize(color): """ Returns an hex color Parameters: ----------- color : string Color representation in rgba|rgb|hex Example: normalize('#f03') """ if type(color) == tuple: color = to_rgba(*color) if 'rgba' in color: return rgb_to_hex(rgba_to_rgb(color)) elif 'rgb' in color: return rgb_to_hex(color) elif '#' in color: if len(color) == 7: return color else: color = color[1:] return '#' + ''.join([x * 2 for x in list(color)]) else: try: return normalize(cnames[color.lower()]) except: raise CufflinksError('Not a valid color: ' + color)
[docs]def rgb_to_hex(color): """ Converts from rgb to hex Parameters: ----------- color : string Color representation on hex or rgb Example: rgb_to_hex('rgb(23,25,24)') """ rgb = eval(color.replace('rgb', '')) # return '#'+''.join(map(chr, rgb)).encode('hex') return '#' + ''.join(['{0:02x}'.format(x).upper() for x in rgb])
[docs]def rgba_to_rgb(color, bg='rgb(255,255,255)'): """ Converts from rgba to rgb Parameters: ----------- color : string Color representation in rgba bg : string Color representation in rgb Example: rgba_to_rgb('rgb(23,25,24,.4)'' """ def c_tup(c): return eval(c[c.find('('):]) color = c_tup(color) bg = hex_to_rgb(normalize(bg)) bg = c_tup(bg) a = color[3] r = [int((1 - a) * bg[i] + a * color[i]) for i in range(3)] return 'rgb' + str(tuple(r))
[docs]def hex_to_hsv(color): """ Converts from hex to hsv Parameters: ----------- color : string Color representation on color Example: hex_to_hsv('#ff9933') """ color = normalize(color) color = color[1:] # color=tuple(ord(c)/255.0 for c in color.decode('hex')) color = (int(color[0:2], base=16) / 255.0, int(color[2:4], base=16) / 255.0, int(color[4:6], base=16) / 255.0) return colorsys.rgb_to_hsv(*color)
[docs]def color_range(color, N=20): """ Generates a scale of colours from a base colour Parameters: ----------- color : string Color representation in hex N : int number of colours to generate Example: color_range('#ff9933',20) """ color = normalize(color) org = color color = hex_to_hsv(color) HSV_tuples = [(color[0], x, color[2]) for x in np.arange(0, 1, 2.0 / N)] HSV_tuples.extend([(color[0], color[1], x) for x in np.arange(0, 1, 2.0 / N)]) hex_out = [] for c in HSV_tuples: c = colorsys.hsv_to_rgb(*c) c = [int(_ * 255) for _ in c] # hex_out.append("#"+"".join([chr(x).encode('hex') for x in c])) hex_out.append("#" + "".join(['{0:02x}'.format(x) for x in c])) if org not in hex_out: hex_out.append(org) hex_out.sort() return hex_out
[docs]def color_table(color, N=1, sort=False, sort_values=False, inline=False, as_html=False): """ Generates a colour table Parameters: ----------- color : string | list | dict Color representation in rgba|rgb|hex If a list of colors is passed then these are displayed in a table N : int number of colours to generate When color is not a list then it generaes a range of N colors sort : bool if True then items are sorted sort_values : bool if True then items are sorted by color values. Only applies if color is a dictionary inline : bool if True it returns single line color blocks as_html : bool if True it returns the HTML code Example: color_table('#ff9933') color_table(cufflinks.cnames) color_table(['pink','salmon','yellow']) Note: This function only works in iPython Notebook """ if isinstance(color, list): c_ = '' rgb_tup = [normalize(c) for c in color] if sort: rgb_tup.sort() elif isinstance(color, dict): c_ = '' items = [(k, normalize(v), hex_to_hsv(normalize(v))) for k, v in list(color.items())] if sort_values: items = sorted(items, key=operator.itemgetter(2)) elif sort: items = sorted(items, key=operator.itemgetter(0)) rgb_tup = [(k, v) for k, v, _ in items] else: c_ = normalize(color) if N > 1: rgb_tup = np.array(color_range(c_, N))[::-1] else: rgb_tup = [c_] def _color(c): if hex_to_hsv(c)[2] < .5: color = "#ffffff" shadow = '0 1px 0 #000' else: color = "#000000" shadow = '0 1px 0 rgba(255,255,255,0.6)' if c == c_: border = " border: 1px solid #ffffff;" else: border = '' return color, shadow, border s = '<ul style="list-style-type: none;">' if not inline else '' for c in rgb_tup: if isinstance(c, tuple): k, c = c k += ' : ' else: k = '' if inline: s += '<div style="background-color:{0};height:20px;width:20px;display:inline-block;"></div>'.format( c) else: color, shadow, border = _color(c) s += """<li style="text-align:center;""" + border + """line-height:30px;background-color:""" + c + """;"> <span style=" text-shadow:""" + shadow + """; color:""" + color + """;">""" + k + c.upper() + """</span> </li>""" s += '</ul>' if not inline else '' if as_html: return s return display(HTML(s))
[docs]def colorgen(colors=None, n=None, scale=None, theme=None): """ Returns a generator with a list of colors and gradients of those colors Parameters: ----------- colors : list(colors) List of colors to use Example: colorgen() colorgen(['blue','red','pink']) colorgen(['#f03','rgb(23,25,25)']) """ step = .1 if not colors: if not scale: if not theme: scale = get_config_file()['colorscale'] else: scale = themes.THEMES[theme]['colorscale'] colors = get_scales(scale) dq = deque(colors) if n: step = len(dq) * 0.8 / n if len(dq) * 8 < n else .1 for i in np.arange(.2, 1, step): for y in dq: yield to_rgba(y, 1 - i + .2) dq.rotate(1)
# NEW STUFF # Color Names # --------------------------------- cnames = {'aliceblue': '#F0F8FF', 'antiquewhite': '#FAEBD7', 'aqua': '#00FFFF', 'aquamarine': '#7FFFD4', 'azure': '#F0FFFF', 'beige': '#F5F5DC', 'bisque': '#FFE4C4', 'black': '#000000', 'blanchedalmond': '#FFEBCD', 'blue': '#3780bf', 'bluegray': '#565656', 'bluepurple': '#6432AB', 'blueviolet': '#8A2BE2', 'brick': '#E24A33', 'brightblue': '#0000FF', 'brightred': '#FF0000', 'brown': '#A52A2A', 'burlywood': '#DEB887', 'cadetblue': '#5F9EA0', 'charcoal': '#151516', 'chartreuse': '#7FFF00', 'chocolate': '#D2691E', 'coral': '#FF7F50', 'cornflowerblue': '#6495ED', 'cornsilk': '#FFF8DC', 'crimson': '#DC143C', 'cyan': '#00FFFF', 'darkblue': '#00008B', 'darkcyan': '#008B8B', 'darkgoldenrod': '#B8860B', 'darkgray': '#A9A9A9', 'darkgreen': '#006400', 'darkgrey': '#A9A9A9', 'darkkhaki': '#BDB76B', 'darkmagenta': '#8B008B', 'darkolivegreen': '#556B2F', 'darkorange': '#FF8C00', 'darkorchid': '#9932CC', 'darkred': '#8B0000', 'darksalmon': '#E9967A', 'darkseagreen': '#8FBC8F', 'darkslateblue': '#483D8B', 'darkslategray': '#2F4F4F', 'darkslategrey': '#2F4F4F', 'darkturquoise': '#00CED1', 'darkviolet': '#9400D3', 'deeppink': '#FF1493', 'deepskyblue': '#00BFFF', 'dimgray': '#696969', 'dimgrey': '#696969', 'dodgerblue': '#1E90FF', 'firebrick': '#B22222', 'floralwhite': '#FFFAF0', 'forestgreen': '#228B22', 'fuchsia': '#FF00FF', 'gainsboro': '#DCDCDC', 'ghostwhite': '#F8F8FF', 'gold': '#FFD700', 'goldenrod': '#DAA520', 'grassgreen': '#32ab60', 'gray': '#808080', 'green': '#008000', 'greenyellow': '#ADFF2F', 'grey': '#808080', 'grey01': '#0A0A0A', 'grey02': '#151516', 'grey03': '#1A1A1C', 'grey04': '#1E1E21', 'grey05': '#252529', 'grey06': '#36363C', 'grey07': '#3C3C42', 'grey08': '#434343', 'grey09': '#666570', 'grey10': '#666666', 'grey11': '#8C8C8C', 'grey12': '#C2C2C2', 'grey13': '#E2E2E2', 'grey14': '#E5E5E5', 'honeydew': '#F0FFF0', 'hotpink': '#FF69B4', 'indianred': '#CD5C5C', 'indigo': '#4B0082', 'ivory': '#FFFFF0', 'java': '#17BECF', 'khaki': '#F0E68C', 'lavender': '#E6E6FA', 'lavenderblush': '#FFF0F5', 'lawngreen': '#7CFC00', 'lemonchiffon': '#FFFACD', 'lightpink2': '#fccde5', 'lightpurple': '#bc80bd', 'lightblue': '#ADD8E6', 'lightcoral': '#F08080', 'lightcyan': '#E0FFFF', 'lightgoldenrodyellow': '#FAFAD2', 'lightgray': '#D3D3D3', 'lightgreen': '#90EE90', 'lightgrey': '#D3D3D3', 'lightivory': '#F6F6F6', 'lightpink': '#FFB6C1', 'lightsalmon': '#FFA07A', 'lightseagreen': '#20B2AA', 'lightskyblue': '#87CEFA', 'lightslategray': '#778899', 'lightslategrey': '#778899', 'lightsteelblue': '#B0C4DE', 'lightteal': '#8dd3c7', 'lightyellow': '#FFFFE0', 'lightblue2': '#80b1d3', 'lightviolet': '#8476CA', 'lime': '#00FF00', 'lime2': '#8EBA42', 'limegreen': '#32CD32', 'linen': '#FAF0E6', 'magenta': '#FF00FF', 'maroon': '#800000', 'mediumaquamarine': '#66CDAA', 'mediumblue': '#0000CD', 'mediumgray': '#656565', 'mediumorchid': '#BA55D3', 'mediumpurple': '#9370DB', 'mediumseagreen': '#3CB371', 'mediumslateblue': '#7B68EE', 'mediumspringgreen': '#00FA9A', 'mediumturquoise': '#48D1CC', 'mediumvioletred': '#C71585', 'midnightblue': '#191970', 'mintcream': '#F5FFFA', 'mistyrose': '#FFE4E1', 'moccasin': '#FFE4B5', 'mustard': '#FBC15E', 'navajowhite': '#FFDEAD', 'navy': '#000080', 'oldlace': '#FDF5E6', 'olive': '#808000', 'olivedrab': '#6B8E23', 'orange': '#ff9933', 'orangered': '#FF4500', 'orchid': '#DA70D6', 'palegoldenrod': '#EEE8AA', 'palegreen': '#98FB98', 'paleolive': '#b3de69', 'paleturquoise': '#AFEEEE', 'palevioletred': '#DB7093', 'papayawhip': '#FFEFD5', 'peachpuff': '#FFDAB9', 'pearl': '#D9D9D9', 'pearl02': '#F5F6F9', 'pearl03': '#E1E5ED', 'pearl04': '#9499A3', 'pearl05': '#6F7B8B', 'pearl06': '#4D5663', 'peru': '#CD853F', 'pink': '#ff0088', 'pinksalmon': '#FFB5B8', 'plum': '#DDA0DD', 'polar': '#ACAFB5', 'polarblue': '#0080F0', 'polarbluelight': '#46A0F0', 'polarcyan': '#ADFCFC', 'polardark': '#484848', 'polardiv': '#D5D8DB', 'polardust': '#F2F3F7', 'polargrey': '#505050', 'polargreen': '#309054', 'polarorange': '#EE7600', 'polarpurple': '#6262DE', 'polarred': '#D94255', 'powderblue': '#B0E0E6', 'purple': '#800080', 'red': '#db4052', 'rose': '#FFC0CB', 'rosybrown': '#BC8F8F', 'royalblue': '#4169E1', 'saddlebrown': '#8B4513', 'salmon': '#fb8072', 'sandybrown': '#FAA460', 'seaborn': '#EAE7E4', 'seagreen': '#2E8B57', 'seashell': '#FFF5EE', 'sienna': '#A0522D', 'silver': '#C0C0C0', 'skyblue': '#87CEEB', 'slateblue': '#6A5ACD', 'slategray': '#708090', 'slategrey': '#708090', 'smurf': '#3E6FB0', 'snow': '#FFFAFA', 'springgreen': '#00FF7F', 'steelblue': '#4682B4', 'tan': '#D2B48C', 'teal': '#008080', 'thistle': '#D8BFD8', 'tomato': '#FF6347', 'turquoise': '#40E0D0', 'violet': '#EE82EE', 'wheat': '#F5DEB3', 'white': '#FFFFFF', 'whitesmoke': '#F5F5F5', 'yellow': '#ffff33', 'yellowgreen': '#9ACD32', "henanigans_bg": "#242424", "henanigans_blue1": "#5F95DE", "henanigans_blue2": "#93B6E6", "henanigans_cyan1": "#7EC4CF", "henanigans_cyan2": "#B6ECF3", "henanigans_dark1": "#040404", "henanigans_dark2": "#141414", "henanigans_dialog1": "#444459", "henanigans_dialog2": "#5D5D7A", "henanigans_green1": "#8BD155", "henanigans_green2": "#A0D17B", "henanigans_grey1": "#343434", "henanigans_grey2": "#444444", "henanigans_light1": "#A4A4A4", "henanigans_light2": "#F4F4F4", "henanigans_orange1": "#EB9E58", "henanigans_orange2": "#EBB483", "henanigans_purple1": "#C98FDE", "henanigans_purple2": "#AC92DE", "henanigans_red1": "#F77E70", "henanigans_red2": "#DE958E", "henanigans_yellow1": "#E8EA7E", "henanigans_yellow2": "#E9EABE" } # Custom Color Scales # --------------------------------- _custom_scales = { 'qual': { # dflt only exists to keep backward compatibility after issue 91 'dflt': ['orange', 'blue', 'grassgreen', 'purple', 'red', 'teal', 'yellow', 'olive', 'salmon', 'lightblue2'], 'original': ['orange', 'blue', 'grassgreen', 'purple', 'red', 'teal', 'yellow', 'olive', 'salmon', 'lightblue2'], 'ggplot': ['brick', 'smurf', 'lightviolet', 'mediumgray', 'mustard', 'lime2', 'pinksalmon'], 'polar': ['polarblue', 'polarorange', 'polargreen', 'polarpurple', 'polarred', 'polarcyan', 'polarbluelight'] }, 'div': { }, 'seq': { } } # --------------------------------------------------------------- # The below functions are based in colorlover by Jack Parmer # https://github.com/jackparmer/colorlover/ # --------------------------------------------------------------- _scales = None _scales_names = None
[docs]def interp(colors, N): def _interp(colors, N): try: return cl.interp(colors, N) except: return _interp(colors, N + 1) c = _interp(colors, N) return list(map(rgb_to_hex, cl.to_rgb(c)))
[docs]def scales(scale=None): """ Displays a color scale (HTML) Parameters: ----------- scale : str Color scale name If no scale name is provided then all scales are returned (max number for each scale) If scale='all' then all scale combinations available will be returned Example: scales('accent') scales('all') scales() """ if scale: if scale == 'all': display(HTML(cl.to_html(_scales))) else: display(HTML(cl.to_html(get_scales(scale)))) else: s = '' keys = list(_scales_names.keys()) keys.sort() for k in keys: scale = get_scales(k) s += '<div style="display:inline-block;padding:10px;"><div>{0}</div>{1}</div>'.format( k, cl.to_html(scale)) display(HTML(s))
# Scales Dictionary # ---------------------------------
[docs]def reset_scales(): global _scales global _scales_names scale_cpy = cl.scales.copy() # Add custom scales for k, v in list(_custom_scales.items()): if v: for k_, v_ in list(v.items()): if str(len(v_)) not in scale_cpy: scale_cpy[str(len(v_))] = {} scale_cpy[str(len(v_))][k][k_] = [ hex_to_rgb(normalize(_)) for _ in v_] # Dictionary by Type > Name > N _scales = {} for k, v in list(scale_cpy.items()): for k_, v_ in list(v.items()): if k_ not in _scales: _scales[k_] = {} for k__, v__ in list(v_.items()): if k__ not in _scales[k_]: _scales[k_][k__] = {} _scales[k_][k__][k] = v__ # Dictionary by Name > N _scales_names = {} for k, v in list(scale_cpy.items()): for k_, v_ in list(v.items()): for k__, v__ in list(v_.items()): k__ = k__.lower() if k__ not in _scales_names: _scales_names[k__] = {} _scales_names[k__][k] = v__
[docs]def get_scales(scale=None, n=None): """ Returns a color scale Parameters: ----------- scale : str Color scale name If the color name is preceded by a minus (-) then the scale is inversed n : int Number of colors If n < number of colors available for a given scale then the minimum number will be returned If n > number of colors available for a given scale then the maximum number will be returned Example: get_scales('accent',8) get_scales('pastel1') """ if scale: is_reverse = False if scale[0] == '-': scale = scale[1:] is_reverse = True d = copy.deepcopy(_scales_names[scale.lower()]) keys = list(map(int, list(d.keys()))) cs = None if n: if n in keys: cs = d[str(n)] elif n < min(keys): cs = d[str(min(keys))] if cs is None: cs = d[str(max(keys))] if is_reverse: cs.reverse() return cs else: d = {} for k, v in list(_scales_names.items()): if isinstance(v, dict): keys = list(map(int, list(v.keys()))) d[k] = v[str(max(keys))] else: d[k] = v return d
[docs]def get_colorscale(scale): """ Returns a color scale to be used for a plotly figure Parameters: ----------- scale : str or list Color scale name If the color name is preceded by a minus (-) then the scale is inversed. Also accepts a list of colors (rgb,rgba,hex) Example: get_colorscale('accent') get_colorscale(['rgb(127,201,127)','rgb(190,174,212)','rgb(253,192,134)']) """ if type(scale) in string_types: scale = get_scales(scale) else: if type(scale) != list: raise Exception( "scale needs to be either a scale name or list of colors") cs = [[1.0 * c / (len(scale) - 1), scale[c]] for c in range(len(scale))] cs.sort() return cs
reset_scales()