Source code for specplot


import os
import sys


[docs]def specplot(hex_, hcl = True, palette = True, fix = True, rgb = False, **kwargs): """specplot(hex_, rgb = True, hcl = True, palette = True, fix = True, **kwargs) Visualization of the RGB and HCL spectrum given a set of hex colors. As the hues for low-chroma colors are not (or poorly) identified, by default a smoothing is applied to the hues (``fix = TRUE``). Also, to avoid jumps from 0 to 360 or vice versa, the hue coordinates are shifted suitably. No return, creates an interactive figure. Parameters ---------- hex_ : list or numpy.ndarray hex color codes. hcl : bool whether or not to plot the HCL color spectrum. palette : bool whether or not to plot the colors as a color map. fix : bool should the hues be fixed to be on a smooth(er) curve? Details in the method description. rgb : bool whether or not to plot the RGB color spectrum. Default is False. kwargs : ... Currently not used. Example ------- >>> from colorspace import rainbow_hcl >>> from colorspace import specplot >>> pal = rainbow_hcl(100) >>> specplot(pal.colors()) >>> specplot(pal.colors(), rgb = False, hcl = True, palette = False) .. todo:: Implement the smoothings to improve the look of the plots. Only partially implemented, the spline smoother is missing. """ # Check if matplotlib is installed or not (as it is not # a package requirement but a suggested package). try: import matplotlib except: raise Exception("Requires matplotlib to be installed! Stop.") # Support function to draw the color map (the color strip) def cmap(ax, hex_): """cmap(ax, hex_) Plotting a color map given a set of colors. Parameters ---------- ax : matplotlib.Axis the axis object on which the color map should be drawn hex_ : list list of hex colors """ from numpy import linspace from matplotlib.patches import Rectangle n = len(hex_) w = 1. / float(n - 1) x = linspace(-w / 2., 1. + w / 2, n + 1) for i in range(0,n): rect = Rectangle((x[i],0.), w, 1., color = hex_[i]) ax.add_patch(rect) # Try to convert inputs to boolean. # raise exception if not possible. try: rgb = bool(rgb); hcl = bool(hcl); palette = bool(palette) except Exception as e: raise Exception(e) # This would yield an empty plot: raise an error. if not rgb and not hcl and not palette: import inspect raise ValueError("disabling rgb, hcl, and palette all at the same time is not possible " + \ "when calling \"{:s}\".".format(inspect.stack()[0][3])) from .colorlib import hexcols coords = {} if not isinstance(hex_, dict): hex_ = {"colors": hex_} # If input parameter "fix = True": fixing # the hue coordinates to avoid jumping which # can occur due to the HCL->RGB transformation. def fixcoords(x): [H, C, L] = x n = len(H) # Number of colors # Fixing spikes import numpy as np for i in range(1,n): d = H[i] - H[i - 1] if np.abs(d) > 320.: H[i] = H[i] - np.sign(d) * 360. if np.abs(H[i]) > 360: H[0:i+1] = H[0:i+1] - np.sign(H[i]) * 360 # Smoothing the hue values in batches where chroma is very low idx = np.where(C < 8.)[0] if len(idx) == n: H = np.repeat(np.mean(H), n) else: # pre-smoothing the hue # Running mean if n > 49: H = 1./3. * (H + np.append(H[0],H[0:-1]) + np.append(H[1:],H[n-1])) # TODO Spline smoother not yet implemented return [H, C, L] # Calculate coordinates coords = {} for key,vals in hex_.items(): cols = hexcols(vals) cols.to("sRGB") coords[key] = {"hex":vals} if rgb: coords[key]["sRGB"] = [cols.get("R"), cols.get("G"), cols.get("B")] if hcl: cols.to("HCL") coords[key]["HCL"] = [cols.get("H"), cols.get("C"), cols.get("L")] if fix: coords[key]["HCL"] = fixcoords(coords[key]["HCL"]) # If we have multiple color maps: disable palette if len(coords) > 1: palette = False from .colorlib import sRGB from .palettes import rainbow_hcl # Specify the colors for the spectrum plots rgbcols = sRGB([0.8, 0, 0], [0, 0.8, 0], [0, 0, 0.8]) hclcols = rainbow_hcl()(4) # Create figure from numpy import linspace, arange import matplotlib.ticker as ticker import matplotlib.pyplot as plt from matplotlib import pyplot as plt # Create plot import numpy as np # The kwargs figure input is used when the specplot # is used as demo plot in the choose_palette interface. if "fig" in kwargs.keys(): fig = kwargs["fig"] else: fig = plt.figure() if rgb and hcl and palette: ax1 = plt.subplot2grid((7, 1), (0, 0), rowspan = 3) ax2 = plt.subplot2grid((7, 1), (3, 0)) ax3 = plt.subplot2grid((7, 1), (4, 0), rowspan = 3) elif rgb and hcl: ax1 = plt.subplot2grid((2, 1), (0, 0)) ax3 = plt.subplot2grid((2, 1), (1, 0)) elif rgb and palette: ax1 = plt.subplot2grid((4, 1), (0, 0), rowspan = 3) ax2 = plt.subplot2grid((4, 1), (3, 0)) elif hcl and palette: ax2 = plt.subplot2grid((4, 1), (0, 0)) ax3 = plt.subplot2grid((4, 1), (1, 0), rowspan = 3) elif rgb: ax1 = plt.subplot2grid((1, 1), (0, 0)) elif hcl: ax3 = plt.subplot2grid((1, 1), (0, 0)) elif palette: # Adjusting outer margins ax2 = plt.subplot2grid((1, 1), (0, 0)) fig.subplots_adjust(left = 0., bottom = 0., right = 1., top = 1., wspace = 0., hspace = 0.) else: import inspect raise ValueError("Unexpected condition in \"{:s}\". Sorry.".format(inspect.stack()[0][3])) # Setting axis properties # ax1: RGB if rgb: ax1.set_xlim(0,1); ax1.set_ylim(0,1); ax1.get_xaxis().set_visible(False) # ax2: color map if palette: ax2.set_xlim(0,1); ax2.set_ylim(0,1); ax2.get_xaxis().set_visible(False) ax2.get_yaxis().set_visible(False) # ax3 and ax33: HCL if hcl: ax3.set_xlim(0,1); ax3.set_ylim(0,100); ax3.get_xaxis().set_visible(False) ax33 = ax3.twinx() ax33.set_ylim(-360,360) # Linestyles (used in case multiple palettes are handed over) linestyles = ["-", "--", "-.", ":"] # Plotting RGB spectrum if rgb: count = 0 for key,val in coords.items(): [R, G, B] = val["sRGB"] x = linspace(0., 1., len(R)) linestyle = linestyles[count % len(linestyles)] LR, = ax1.plot(x, R, color = rgbcols.colors()[0], linestyle = linestyle) LG, = ax1.plot(x, G, color = rgbcols.colors()[1], linestyle = linestyle) LB, = ax1.plot(x, B, color = rgbcols.colors()[2], linestyle = linestyle) count += 1 #ax1.legend([LR, LG, LB], ["R", "G", "B"], # bbox_to_anchor = (0., 1., .3, 0.), ncol = 3, frameon = False) # Plotting the color map if palette: cmap(ax2, coords[list(coords.keys())[0]]["hex"]) # Plotting HCL spectrum if hcl: count = 0 for key,val in coords.items(): [H, C, L] = val["HCL"] x = linspace(0., 1., len(H)) linestyle = linestyles[count % len(linestyles)] ax3.plot(x, C, color = hclcols[1], linestyle = linestyle) ax3.plot(x, L, color = hclcols[2], linestyle = linestyle) ax33.plot(x, H, color = hclcols[0], linestyle = linestyle) count += 1 ax33.set_yticks(arange(-360, 361, 120)) ax33.yaxis.set_major_formatter(ticker.FormatStrFormatter('%0.0f')) # Labels and annotations if rgb: ax1.set_ylabel("Red/Green/Blue") ax1.xaxis.set_label_position("top") ax1.text(0.5, 1.05, "RGB Spectrum", horizontalalignment = "center", verticalalignment = "bottom") if hcl: ax3.set_ylabel("Chroma/Luminance") ax33.set_ylabel("Hue") ax3.text(0.5, -10, "HCL Spectrum", horizontalalignment = "center", verticalalignment = "top") if not "fig" in kwargs.keys(): plt.show()