Color Map Utilities¶
Matplotlib provides numerous built-in colormaps and an excellent tutorial on Choosing Colormaps. Various colormaps and styles third party packages are available that extend Matplotlib.
Familiarity with these built-in color maps is suggested. The sequential built-in maps are particularly useful for 3D surface visualizations.
Choosing colormaps for surfaces in 3D has the additional requirement of enhancing the geometric visualization along with defining functional values. S3Dlib provides multiple easy-to-use methods for creating custom colormaps which are particularly applicable for displaying 3D surfaces. These methods are particularly useful when transparent and mirrored colormaps are needed for clear visualizations of 3D surfaces, or simply for a more graphic display. All colormaps using these functions are derived from matplotlib.colors.Colormap. These functions are available in the module:
import s3dlib.cmap_utilities as cmu
In the following discussion, example colormaps are provided to illustrate the usage of the S3Dlib methods.
RGB Linear Gradient¶
Simple color maps, linear in RGB space, are created using the function
cmu.rgb_cmap_gradient(lowColor,highColor,name=None,mirrored=False)
which returns an instance of a registered matplotlib.colors.Colormap with name. When name is None, the name is assigned an eight-character string of random upper-case letters. The color arguments are in Matplotlib Colors format. The colormap monotonically increases from the lowColor to the highColor in RGB color space. The mirrored argument is a boolean and if set True, the color map is mirrored with the highcolor at the center. Mirrored colormaps are particularly useful for non-orientable surfaces. See Non-Orientable Surface.
Several examples using this function are:
cmaps['RGB Gradient'] = [
'rgbDefault', 'mpDefault',
'RdToGn', 'YWToBu', 'cardboard', 'cardboardMrrd',
'bnShade', 'WtToBk', 'BkToWtMrrd', 'WtToBkMrrd' ]
cmu.rgb_cmap_gradient( name='rgbDefault')
cmu.rgb_cmap_gradient( 'black', [0.122, 0.467, 0.706], 'mpDefault' )
cmu.rgb_cmap_gradient( 'red', 'green', 'RdToGn' )
cmu.rgb_cmap_gradient( 'yellow', 'blue', 'YWToBu' )
cmu.rgb_cmap_gradient( [0.25,0.15,0], [1,.9,.75], 'cardboard' )
cmu.rgb_cmap_gradient( [0.25,0.15,0], [1,.9,.75], 'cardboardMrrd', mirrored=True )
cmu.rgb_cmap_gradient( [0.25,0.15,0], 'white', 'bnShade' )
cmu.rgb_cmap_gradient( 'white', 'black', 'WtToBk' )
cmu.rgb_cmap_gradient( 'black', 'white', 'BkToWtMrrd', mirrored=True )
cmu.rgb_cmap_gradient( 'white', 'black', 'WtToBkMrrd', mirrored=True )
Note that the colormap with assigned name ‘rgbDefault’ is the default colormap if no color arguments are provided.
HSV Linear Gradient¶
Simple color maps, linear in HSV space, are created using the function
cmu.hsv_cmap_gradient(lowHSV,hiHSV,name=None,mirrored=False)
which returns an instance of a registered matplotlib.colors.Colormap with name. When name is None, the name is assigned an eight-character string of random upper-case letters. The lowHSV and hiHSV are HSV or HSVA (hue, saturation, value, alpha) arrays of float values. The float values for SVA range in [0,1].
The float values for hue range in [0,2], which is not the standard range for hue. This was defined in this manner to allow for direction in the cyclic definition of hue. This hue mapping from 0 to 2 is shown below.
For example, consider a color map going from green (low) to blue (high). Specifying green and blue as 0.33 and 0.67, the map will pass through cyan. However, specifying green as 1.33, the map will pass through yellow, red and magenta. The colormap still monotonically increases from the lowColor to the highColor in HSV space. The mirrored argument is applied in the same manner as previously described for the RGB gradient color maps.
Hue¶
The following are examples of varying the cyclic hue value of the color arguments in both the forward and backward directions. In these examples, the saturation and value for the low and high color arguments were held constant at 1.
cmaps['Hue Gradient'] = [
'hsvDefault',
'hsvRdToGn', 'hsvRdFromGn', 'hsvYwToBu','hsvYwFromBu',
'RdToRd', 'RdFromRd', 'RdToRdMrrd', 'RdFromRdMrrd',
'BlToBl', 'BlFromBl', 'BlToBlMrrd', 'BlFromBlMrrd' ]
cmu.hsv_cmap_gradient( name='hsvDefault')
cmu.hsv_cmap_gradient( [0,1,1], [0.333,1,1], 'hsvRdToGn' )
cmu.hsv_cmap_gradient( [1,1,1], [0.333,1,1], 'hsvRdFromGn' )
cmu.hsv_cmap_gradient( [0.166,1,1], [0.666,1,1], 'hsvYwToBu' )
cmu.hsv_cmap_gradient( [1.166,1,1], [0.666,1,1], 'hsvYwFromBu' )
cmu.hsv_cmap_gradient( [0,1,1], [1,1,1], 'RdToRd' )
cmu.hsv_cmap_gradient( [1,1,1], [0,1,1], 'RdFromRd' )
cmu.hsv_cmap_gradient( [0,1,1], [1,1,1],'RdToRdMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [1,1,1], [0,1,1],'RdFromRdMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [0.666,1,1], [1.666,1,1], 'BlToBl' )
cmu.hsv_cmap_gradient( [1.666,1,1], [0.666,1,1], 'BlFromBl' )
cmu.hsv_cmap_gradient( [0.666,1,1], [1.666,1,1], 'BlToBlMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [1.666,1,1], [0.666,1,1], 'BlFromBlMrrd', mirrored=True )
Note that the colormap with the assigned name ‘hsvDefault’ is the default colormap if no color arguments are provided. This colormap is equivalent to the Matplotlib built-in colormap named ‘hsv.’
The effect of reversing the order of the low and high color arguments is most notable by comparing the maps ‘RdToRd’ versus ‘RdFromRd’. Both start and end with red. Also, the difference between using RGB and HSV is seen by comparing the yellow to blue colormaps in these two-color spaces, ‘YwToBu’ versus ‘hsvYwToBu’.
Saturation and Value¶
In these examples, the hue was constant at 0 (red). The first four colormaps vary value [0,1] while holding saturation to 1. The second set varies saturation [0,1] and hold value constant at 1.
cmaps['Saturation and Value Gradient'] = [
'RdToBk', 'BkFromRd', 'RdToBkMrrd', 'BkFromRdMrrd',
'RdToWt', 'WtFromRd', 'RdToWtMrrd', 'WtFromRdMrrd' ]
cmu.hsv_cmap_gradient( [0,1,1], [0,1,0], 'RdToBk' )
cmu.hsv_cmap_gradient( [0,1,0], [0,1,1], 'BkFromRd' )
cmu.hsv_cmap_gradient( [0,1,1], [0,1,0], 'RdToBkMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [0,1,0], [0,1,1], 'BkFromRdMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [0,1,1], [0,0,1], 'RdToWt' )
cmu.hsv_cmap_gradient( [0,0,1], [0,1,1], 'WtFromRd' )
cmu.hsv_cmap_gradient( [0,1,1], [0,0,1], 'RdToWtMrrd', mirrored=True )
cmu.hsv_cmap_gradient( [0,0,1], [0,1,1], 'WtFromRdMrrd', mirrored=True )
Cyclic and Named Colors¶
Since the hue is cyclic, any same hue can be represented by a number plus an integer value. For example, blue hue is 0.67, 1.67, 2.66, 3.67, etc. This results in the ability to produce repeated color maps by representing the low and high arguments with values greater than 2.
Also, the arguments can be strings of named Matplotlib colors. See for example named colors. To shift the named color hues above 1, the color string is prefixed with a ‘+’ character. This provides the method of reversing the direction of the hue while still using named color values.
Examples using cyclic and named color for HSV color maps are:
cmaps['Cyclic and Named Color'] = [
'red3', 'blue2R', 'goldteal', 'plgrnOrchR',
'pgrdkcy', 'hpnktrq', 'pgrdkcy_RGB', 'hpnktrq_RGB' ]
cmu.hsv_cmap_gradient( [0,1,1], [3,1,1], 'red3' )
cmu.hsv_cmap_gradient( [2.666,1,1], [0.666,1,1], 'blue2R' )
cmu.hsv_cmap_gradient( 'gold','teal', 'goldteal' )
cmu.hsv_cmap_gradient( '+palegreen','orchid', 'plgrnOrchR' )
cmu.hsv_cmap_gradient( 'palegoldenrod','darkcyan', 'pgrdkcy' )
cmu.hsv_cmap_gradient( 'hotpink','turquoise', 'hpnktrq' )
cmu.rgb_cmap_gradient( 'palegoldenrod','darkcyan', 'pgrdkcy_RGB' )
cmu.rgb_cmap_gradient( 'hotpink','turquoise', 'hpnktrq_RGB' )
This produces the following colormaps.
In the above, the last two colormaps use the RGB gradient method as a comparison to the map produced by the HSV gradient method which precedes them. This exemplifies the effect of a reduction in saturation and value while linearly moving through RGB space.
Hue HSV Modifications¶
While varying hue in HSV color space, there is an apparent ‘sharpness’ or rapid change in apparent color at yellow, cyan, and magenta. This is seen in ‘hsv’ colormap shown below.
This perceptual change is also reflected in the rapid change in CIELAB color space represented by lightness, L*. (A more detailed discussion of this is in Choosing Colors in Matplotlib ).
To smooth-out this sharpness in the HSV colormap, the following method is available:
cmu.hue_cmap(lowHue=0, hiHue=None, smooth=1.6, name=None)
Which returns a colormap of constant value and saturation of 1. The smooth parameter is the degree of smoothing at yellow, cyan and magenta, with a value of 1 for no smoothing. For values greater than one, hues around yellow, cyan and magenta are expanded, reducing the extent of red, green and blue hues. For values less than one, the opposite occurs. The smooth value range is [0.1,10]. The default value is 1.6. The parameters lowHue and highHue are similary defined for the hue as given in the previous sections. When color names are used for this parameter, only the hue value of the color is used.
Example colormaps using this method are given below.
cmaps['Hue HSV'] = [
'hue_05', 'hsvDefault', 'HUEdefault','hue_80',
'hueYwToYw8', 'hueYwToBu8', 'hueYwFromBu8', 'hueYwFromBu5' ]
cmu.hue_cmap( name='HUEdefault' )
cmu.hue_cmap(smooth=8.0,name='hue_80')
cmu.hue_cmap(smooth=0.5,name='hue_05' )
cmu.hue_cmap( 0.166,smooth=8.0, name='hueYwToYw8')
cmu.hue_cmap('y', 'b',8.0, 'hueYwToBu8')
cmu.hue_cmap('+y','b',8.0, 'hueYwFromBu8')
cmu.hue_cmap('+y','b',0.5, 'hueYwFromBu5')
The effect of lightness, L*, on smoothing is shown in the grayscale maps below, for the first four colormaps.
A qualitative description of smoothing by examining the L* numerical values is shown in the plot below. The effect of smoothing is illustrated in this plot showing the peaks, valleys and plateaus of the lightness curves at CMY (0.167, 0.5, 0.833) and RGB (0.0, 0.33, 0.67).
The script for producing the above plot is given below.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colormaps
from matplotlib.colors import ListedColormap
from colorspacious import cspace_converter
import s3dlib.cmap_utilities as cmu
def Lstar(cmap) :
''' x,y arrays for ploting L* of a colormap.'''
if isinstance(cmap,str) : cmap = colormaps[cmap]
N = 256
if isinstance(cmap,ListedColormap) : N = len(cmap.colors)
rgb = cmap(range(N))[:,0:3]
lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb)
L = np.transpose(lab)[0]
x = np.linspace(0, 1, N)
return x,L
# ...................................................
vhsv, Lhsv = Lstar('hsv')
vdflt, Ldflt = Lstar(cmu.hue_cmap())
v_80, L_80 = Lstar(cmu.hue_cmap(smooth=8))
v_05, L_05 = Lstar(cmu.hue_cmap(smooth=0.5))
fig = plt.figure(figsize=(6,2.5))
ax = fig.add_subplot(1,1,1)
ax.set(xlim=(0,1), ylim=(0,100))
ax.set_ylabel('L* value')
ax.plot(v_05,L_05, label='0.5 ', color='g', linestyle='-.')
ax.plot(vhsv, Lhsv, label='1.0, HSV', color='k')
ax.plot(vdflt, Ldflt, label='1.6, default', color='r')
ax.plot(v_80,L_80, label='8.0 ', color='y', linestyle=':')
ax.legend()
plt.show()
The effect of smoothing out an HSV colormap when applied to a surface is shown in the simple surface plot below.
Smooth HSV¶
The ‘smooth’ parameter is also available when using the hsv_cmap_gradient method. This effect is most apparent when creating colormaps between the RGB colors. The regular and smooth colormaps are shown as a comparison.
cmaps['Smoothed HSV'] = [
'RG', 'RG_s', 'GB','GB_s',
'BR', 'BR_s']
cmu.hsv_cmap_gradient( [0,1,1], [0.333,1,.65], 'RG' )
cmu.hsv_cmap_gradient( [0,1,1], [0.333,1,.65], 'RG_s', smooth=1.6 )
cmu.hsv_cmap_gradient( [.333,1,.34], [0.666,1,1], 'GB' )
cmu.hsv_cmap_gradient( [.333,1,.34], [0.666,1,1], 'GB_s', smooth=1.4 )
cmu.hsv_cmap_gradient( [0.666,1,1], [0.999,1,.52], 'BR' )
cmu.hsv_cmap_gradient( [0.666,1,1], [0.999,1,.52], 'BR_s', smooth=1.6 )
In these examples, the red and green values were selected with reduced values to create maps with similar starting and ending L* values, as seen in the following plot.
Lab Linear Gradient¶
A colormap with a linearly monotonic increasing L* values may be preferable for increased perception when used for illustrating surface geometries. This type of map is also beneficial when surface geometry visualization is needed when printed on black and white printers. Numerous sequential colormaps to choose from are by Matplotlib in the section Sequential.
The cmap_xtra file provides the Lab_cmap_gradient method to construct colormaps which are linear in Lab space. Consequently, these maps will be linear in L*. Linear Lab colormaps are created using a function from a file and creating the cmap as:
import s3dlib.cmap_xtra as cmx
cmap = cmx.Lab_cmap_gradient(lowColor='k', highColor='w', name=None, mirrored=False)
All calling parameters are identical to those used in the rgb_cmap_gradient method.
Examples of colormaps using Lab_cmap_gradient are given below.
cmaps['Lab Gradient'] = [
'magma', 'viridis', 'lab_indg','lab_marn',
'lab_dgrn', 'lab_RdWt', 'RdToWt' ]
cmx.Lab_cmap_gradient('indigo', 'aqua', 'lab_indg')
cmx.Lab_cmap_gradient('maroon', 'yellow', 'lab_marn')
cmx.Lab_cmap_gradient('darkgreen','lemonchiffon','lab_dgrn')
cmx.Lab_cmap_gradient('red', 'white', 'lab_RdWt')
The resulting colormaps are below. The linear Matplotlib colormaps of ‘magma’ and ‘viridis’ are shown as a comparison to those generated using this function.
Grayscale maps for these colormaps illustrate the perceived lightness values.
The plot below quantitatively demonstrates the linear nature of the colormaps and the relative differences between the maps.
Lab Linear, Hue Constant Gradient¶
Colormap having a linear lightness gradient from a low, lowL, to a high, hiL, with a constant value of hue can be produced using the method:
import s3dlib.cmap_xtra as cmx
cmap = cmx.Hue_Lab_gradient(color,lowL=0.0, hiL=1.0, name=None)
where color is a Matplotlib named color, a three-element list or a single numerical value which will be used to set the H value of the gradient. The range for the lowL and hiL arguments is [0,1]. For example, using this method as:
cmaps['Hue Lab Gradient'] = [
'gray','red_L', 'yellow_L', 'green_L', 'cyan_L', 'blue_L','magenta_L' ]
cmx.Hue_Lab_gradient('red')
cmx.Hue_Lab_gradient('yellow')
cmx.Hue_Lab_gradient('green')
cmx.Hue_Lab_gradient('cyan')
cmx.Hue_Lab_gradient('blue')
cmx.Hue_Lab_gradient('magenta')
results in colormaps as:
with corresponding L* plots:
Colormaps with a linear gradient in L* may be a substitute for the shading using the surface method map_cmap_from_normal. The following is a comparison among the above colormaps when surface mapping to a sphere.
In the above figure, the Matplotlib named colormap ‘gray’ and shading a white sphere is also shown as a reference.
Lab Linear of a Colormap¶
Colormaps having a linear lightness gradient from a low, lowL, to a high, hiL, with a colormap hue of maximum Saturation can be produced using the method:
import s3dlib.cmap_xtra as cmx
cmap = cmx.Hue_Lab_gradient(colormap, lowL=None, hiL=None, name=None)
where colormap is a colormap, which will be to set the H values of the gradient.
If assigned, the range for the lowL and hiL arguments is [0,1]. If not defined, the domain is the range taken from the colormap. For example, using this method as:
cmNm = ['viridis','plasma','Reds','YlGn','spring','autumn','copper']
cPairs = zip( cmNm , [ n+'_L' for n in cmNm] )
clst = [item for sub_list in cPairs for item in sub_list]
cmaps['Cmap Lab Gradient'] = clst
for cmVal in clst : cmx.Cmap_Lab_gradient(cmVal)
results in colormaps as:
with corresponding L* plots:
This method is most suitable using sequential colormaps since the resulting colormap is linear from start to finish. The effect of this method is to, in general, increase the color saturation of the colormap when the second-derivative of L* is negative. This is seen in the Matplotlib colormaps of viridis, plasma, Reds, YlGn, and copper. The opposite effect of reducing saturation occurs for colormaps with positive derivativess, evident for spring and autumn.
Stitch Cmaps¶
Colormaps may be created from concatenated colormaps using
cmu.stitch_cmap( *maps, bndry=None, name=None)
which returns an instance of a registered matplotlib.colors.Colormap with name. When name is None, the name is assigned an eight-character string of random upper-case letters. The bndry argument is a float or a list of float values designating the boundaries between the input maps. Values range from greater than 0 to less than 1. If bndry is None (default), the input maps are evenly spaced.
cmaps['Stitch'] = [
'fWt_2', 'inferno_3', 'RdCy_4',
'Diverging*', 'Cyclic*', 'stchG' ]
cmA = cmu.hsv_cmap_gradient('firebrick','wheat',smooth=1.5)
cmB = cmu.hsv_cmap_gradient('wheat','teal',smooth=1.5)
cmu.stitch_cmap(cmA,cmB,name='fWt_2')
cmu.mirrored_cmap('inferno',rev=True)
testMap3 = cmu.stitch_cmap('inferno','inferno_mr','inferno_r',bndry=[0.2,0.6],name='inferno_3' )
cmu.reversed_cmap('RdToBk')
cmu.hsv_cmap_gradient( [0.5,1,1], [0.5,1,0], 'CyToBk' )
cmu.reversed_cmap('CyToBk')
cmu.stitch_cmap('RdToBk_r', 'RdToBk','CyToBk_r', 'CyToBk',bndry=[0.3,0.5,0.8], name='RdCy_4' )
cmC = cmx.Lab_cmap_gradient('olive','paleturquoise')
cmD = cmx.Lab_cmap_gradient('paleturquoise','mediumslateblue')
cmu.stitch_cmap(cmC,cmD,name='Diverging*')
cmE,cmF = cmx.Lab_cmap_gradient('black','mediumvioletred'), cmx.Lab_cmap_gradient('mediumvioletred','white'),
cmG,cmH = cmx.Lab_cmap_gradient('white','green'), cmx.Lab_cmap_gradient('green','black')
cmu.stitch_cmap(cmE,cmF,cmG,cmH,name='Cyclic*')
cmu.hsv_cmap_gradient( [0,1,.8], [0,0,1], 'redG')
cmu.hsv_cmap_gradient( 'saddlebrown', 'yellow', 'yelG')
cmu.hsv_cmap_gradient( 'darkgreen', 'lime', 'grnG')
cmu.hsv_cmap_gradient( 'darkslategray', 'cyan', 'cynG')
cmu.hsv_cmap_gradient( 'midnightblue', 'deepskyblue', 'bluG')
cmu.hsv_cmap_gradient( [0.833,1,0.1], 'magenta', 'mgnG')
cmu.stitch_cmap( 'mgnG','bluG','cynG', 'grnG','yelG', 'redG', name='stchG' )
This method can be used to construct simple linear tricolor or multi-color colormaps, for example fWt_2. Specific colormap values can be emphasized using this method as seen in the inferno_3 and RdCy_4 examples, (0.2, 0.6) and (0.3,0.8) respectively. Using Lab colormaps, Diverging and Cyclic colormaps can be constructed.
Stitch Colors¶
Simple multi-color maps are created using the function:
cmu.stitch_color(*colorVals, bndry=None, name=None )
which returns an instance of a registered matplotlib.colors.Colormap with name. When name is None, the name is assigned an eight-character string of random upper-case letters. The bndry argument is a float or a list of float values designating the boundaries between the input colors. Values range from greater than 0 to less than 1. If bndry is None (default), the input colors are evenly spaced.
The following is equivalent for two-color colormaps:
cmu.binary_cmap(negColor='b',posColor='r',name=None,bndry=None)
but in this case, the division between the colors are set by the single float bndry argument, which ranges from 0.03 to 0.97, with a default value of 0.5. Binary colormaps are particularly useful for having different colors for front and back surfaces. For example, see Inner/Outer Surface Colormap and Inner and Outer Surface Coloring.
cmaps['Multi-color'] = [
'binaryDefault', 'binaryRdBu', 'rygcb', 'binaryBuGnLw' ]
cmu.binary_cmap( name='binaryDefault' )
cmu.binary_cmap( [1,0,0], [0,0,1], 'binaryRdBu' )
cmu.stitch_color( 'red', 'yellow', 'green', 'cyan','blue', bndry=[0.1,.4,.7,.8,],name='rygcb' )
cmu.binary_cmap( [0,0,.5], [0,.5,0], 'binaryBuGnLw',0.33 )
Mirrored and Reversed¶
Any registered colormap can have the order reversed using
cmu.reversed_cmap(cmap,name=None)
which returns a new instance of a registered colormap. The returned colormap name is the cmap name with the suffix ‘_r’.
Any registered colormap can be used to create a mirrored color map using
cmu.mirrored_cmap(cmap,name=None,rev=False)
The returned colormap name is the cmap name with the suffix ‘_m’. If the rev argument is True, the returned colormap is also reversed and the name has the suffix ‘_mr’.
cmaps['Mirrored and Reversed'] = [
'viridis', 'plasma', 'magma', 'cividis',
'viridis_r', 'plasma_r', 'magma_r', 'cividis_r',
'viridis_m', 'plasma_m', 'magma_m', 'cividis_m',
'viridis_mr', 'plasma_mr', 'magma_mr', 'cividis_mr' ]
cmu.reversed_cmap('viridis')
cmu.reversed_cmap('plasma')
cmu.reversed_cmap('magma')
cmu.reversed_cmap('cividis')
cmu.mirrored_cmap('viridis')
cmu.mirrored_cmap('plasma')
cmu.mirrored_cmap('magma')
cmu.mirrored_cmap('cividis')
cmu.mirrored_cmap('viridis', rev=True)
cmu.mirrored_cmap('plasma', rev=True)
cmu.mirrored_cmap('magma', rev=True)
cmu.mirrored_cmap('cividis', rev=True)
Creating Cmaps Using Functions¶
The previous functions provide methods for creating colormaps which are linear in RGB, HSV or Lab color spaces. For a more general approach, colormaps may be created using a function returning the color component values using
cmu.op_cmap(op,rgb=True,name=None)
where op is a function that takes one argument, a N Numpy array of float numbers in the domain of 0 to 1. The function returns a 3XN or 4XN array of color values. By default, RGB or RGBA color values are returned by the operation function. If the rgb argument is set False, the operation returns HSV color values.
This returns a registered colormap with the name given by the name argument. When name is None, the colormap is named using the function name. For a lambda function, the name is assigned an eight-character string of random upper-case letters.
def demoRGB(t): #... function for RGB
r = (0.5*( 1+ np.cos(2*np.pi*t) ))**2
g = (0.5*( 1+ np.sin(2*np.pi*t) ))**2
b = t*1
return r,g,b
def demoHSV(t) : #... function for HSV (smoothed 'jet' like)
rgb = cmu.hsv_cmap_gradient( [0.67,1,1],[0,1,1],smooth=1.6)(t)[:,0:3]
h,s,v = cm.colors.rgb_to_hsv(rgb).T
S = 1 - .5*(np.sin(np.pi*t))**3
V = 0.5 + 0.5*(np.sin(np.pi*t)**0.5)
return h,S,V
def cmapSect(t,cmap,s,e) : return colormaps[cmap](s + (e-s)*t).T # rev. mpl v_3.8
def midTerrain(t) : return cmapSect(t,'terrain',.25,.75) # function using Matplotlib 'terrain'
def RGBAtrans(t) : #... function for RGBA using Matplotlib 'hsv'
r,g,b,a = colormaps['hsv'](t).T # rev. mpl v_3.8
a = (0.5*( 1+ np.cos(6*np.pi*t) ))**6
return r,g,b,a
def CMYblack(t): #... function for HSV
s = np.full(len(t),1)
v = (0.5*( 1- np.cos(6*np.pi*t) ))**6
return t,s,v
cmu.op_cmap(midTerrain)
cmu.op_cmap(demoHSV,False)
cmu.op_cmap(demoRGB)
cmu.op_cmap(RGBAtrans)
cmu.op_cmap(CMYblack,False)
cmaps = [ 'demoRGB', 'jet', 'demoHSV', 'terrain', 'midTerrain', 'hsv', 'RGBAtrans', 'CMYblack' ]
Note that in the above script and plot, the function names are assigned to the colormap names since the name argument was not defined when op_cmap was called.
The colormap utilities also include the section_cmap function which creates a colormap from a predefined colormap, similar to the midTerrain example shown above.
Transparency¶
Any registered colormap can have the transparency set using
cmu.alpha_cmap(cmap,alpha,constant=False,name=None)
where cmap argument is a cmap or a registered colormap name. The argument alpha ranges from 0 to 1 for fully transparent to opaque, respectively. This function will create and return a cmap with a name with suffix ‘_a’. The argument constant default is False, in which case, all alpha values of the returned colormap are the input values multiplied by alpha. When constant is set to True, all colors in the map will have the same alpha value.
When only the alpha channel is to be modified from a registered colormap, use the method:
cmu.op_alpha_cmap( cmap,operation,fit=True,name=None )
where cmap is a registered colormap and operation is a function returning a numerical value in the domain 0 to 1. When fit is True, the function range is adjusted from 0 to 1. Otherwise, the return value of the operation must be in the range of 0 to 1. There are two advantages of using this method, compared to the op_cmap method. First, the same function may be applied for different colormaps. Second, using the default for fit, the function range is conveniently set from 0 to 1.
def gapJet(t) :
r,g,b,a = colormaps['jet'](t).T # rev. mpl v_3.8
gap = np.logical_and( t>0.4, t<0.6 )
a = np.where(gap,np.zeros(a.shape),np.ones(a.shape))
return r,g,b,a
cmu.op_cmap(gapJet)
def cosfunc(t) : return np.cos(2*np.pi*t)
# .....................................................................
cmu.alpha_cmap('jet',0.5)
cmu.alpha_cmap('gapJet',0.5)
cmu.alpha_cmap('gapJet',0.5,True,'gapJet_a_True')
cmu.op_alpha_cmap('jet',cosfunc,name='jet_op')
cmu.op_alpha_cmap('cool',cosfunc,name='cool_op')
cmaps = [ 'jet', 'jet_a', 'gapJet', 'gapJet_a', 'gapJet_a_True','jet_op','cool','cool_op']
In the above example, the gapJet colormap was created to demonstrate the effect of True or False values for the constant argument using an initial colormap with transparency values.
DualCmap¶
Colormaps map one independent variable, u, to a color, i.e., RGBA = f(u). A DualCmap class object provides a means of mapping two independent variables, u and v, to a color, RGBA = g(u,v). Instead of using an object.map_cmap_from_op method, a two-dimensional colormap may be used with the object.map_color_from_op method which is passed a function as:
def op_function(xyz) :
u,v = f(xyz)
return dcmap( u,v )
where f(xyz) is a function of xyz and dcmap is an instance of the DualCmap class. DualCmap objects are constructed from two colormaps, xcmap and ycmap, as:
dcmap = cmu.DualCmap( xcmap, ycmap, kind='sum', norm=True )
where kind indicates the method of combining colormap colors. Values are either predefined types of combinations (‘sum’,’ave’,’ave2’,’srt’) or a float in the range 0.2 to 4.0. The argument norm indicates if the method arguments are to be normalized. Otherwise, the calling arguments to the instance, u and v, should be in the range 0 to 1.
Using the following colormaps:
the resulting DualCmaps can be constructed:
The following examples demonstrate using a DualCmap object:
- Complex Number DualCmap where kind is ‘srt’ or 1.5
- Surface Face Distribution DualCmap where kind is the default ‘sum’
- Compound DualCmap where kind is ‘ave’
- Four-Color DualCmap where kind is ‘ave’
Miscellaneous¶
Color Space Cmap Comparisons¶
The colormap functions provide the creation of colormaps which are linear in RGB, HSV or Lab colorspace. A comparison between the differences is shown below using the same initial and final colors for the colormaps. The Matplotlib ‘Blues’ colormap is used as the reference colormap.
The lightness, L*, for these colormaps is compared below.
Since the Lab, HSV_Lab and Blues_L colormaps are linear in Lab space, these line-plots overlap. A visualization of several linear colormaps in both Lab and RGB colorspace are included in the Matplotlib Colormaps example.
The above colormaps were generated using the following script fragment:
from colorspacious import cspace_converter
blues = colormaps['Blues']
strRGB = cm.colors.to_rgb(blues(0.0))
endRGB = cm.colors.to_rgb(blues(1.0))
strHSV = cm.colors.rgb_to_hsv(strRGB)
endHSV = cm.colors.rgb_to_hsv(endRGB)
strLab = cspace_converter("sRGB1", "CAM02-UCS" )(strRGB)
endLab = cspace_converter("sRGB1", "CAM02-UCS" )(endRGB)
sLab = strLab[0]/100
eLab = endLab[0]/100
cm_rgb = cmu.rgb_cmap_gradient(strRGB,endRGB,name='RGB')
cm_hsv = cmu.hsv_cmap_gradient(strHSV,endHSV,name='HSV')
cm_lab = cmx.Lab_cmap_gradient(strRGB,endRGB,name='Lab')
cm_Hlb = cmx.Hue_Lab_gradient(endRGB,sLab,eLab,name='Hue_Lab')
cm_Blu = cmx.Cmap_Lab_gradient('Blues')
cmaps = [cm_rgb,cm_hsv,cm_lab,cm_Hlb,cm_Blu,'Blues']
Colormap Figures¶
Any colormaps can be readily analyzed and compared using the cmap_xtra function:
show_cmaps(plt,cmaps,onlyColormaps=True,show=True)
where plt is matplotlib.pyplot and cmaps is a list of colormaps. The colormap list can also include strings, the names of registered colormaps.
Three figures are generated: colormap images, grayscale colormap images and L* plot. If only the colormap figure is to be generated, the boolean onlyColormaps is set True (the default). By default, the matplotlib.pyplot method show() will be called unless the show argument is set to False.
The following demonstrates three figures for a set of example colormaps.
Visual color scale.
Visual L* gray scale.
x versus L* line plot.
Note that the x,L* plot does not reflect the alpha channel of the colormap.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm, colormaps
import s3dlib.cmap_utilities as cmu
import s3dlib.cmap_xtra as cmx
#.. Demo use of show_cmaps: colormap figures
# 1. Define colormaps to examime .........................................
def RGBAtrans(t) : #... function for RGBA
r,g,b,a = colormaps['hsv'](t).T # rev. mpl v_3.8
a = (0.5*( 1+ np.cos(6*np.pi*t) ))**6
return r,g,b,a
def demoHSV(t) : #... function for HSV (smoothed 'jet' like)
rgb = cmu.hsv_cmap_gradient( [0.67,1,1],[0,1,1],smooth=1.6)(t)[:,0:3]
h,s,v = cm.colors.rgb_to_hsv(rgb).T
S = 1 - .5*(np.sin(np.pi*t))**3
V = 0.5 + 0.5*(np.sin(np.pi*t)**0.5)
return h,S,V
cmu.hue_cmap(smooth=8.0,name='hue_80')
cmu.hsv_cmap_gradient( [0,1,1], [0.333,1,.65], 'RG_s', smooth=1.6 )
cmx.Lab_cmap_gradient('darkgreen','lemonchiffon','lab_dgrn')
cmu.binary_cmap( 'blue', 'yellow', 'binaryBuYw' )
cmu.op_cmap(RGBAtrans)
cmu.alpha_cmap('jet',0.5)
cmu.op_cmap(demoHSV,False)
# 2. Construct figure and plot ...........................................
cmaps = [ 'hue_80', 'RG_s', 'lab_dgrn', 'binaryBuYw', 'RGBAtrans', 'jet_a', 'demoHSV' ]
cmx.show_cmaps(plt,cmaps,False)
Named Colors¶
There are numerous available colors in the List of named colors in Matplotlib, sorted by hsv color value. When constructing custom colormaps, comparing colors based on the Lab color values is often convenient. The following table lists the named CSS colors sorted by Lab color.
Summary Table¶
The above colormaps were generated using the following script fragment:
def RYGCBM(t): #... function for op_cmap
v = (0.5*( 1+np.cos(12*np.pi*t) ))**6
return t, np.ones(len(t)), v #.. HSV
cmu.rgb_cmap_gradient('red','blue', name='1.')
cmu.hue_cmap ('+red','blue', 1.6, name='2.')
cmu.hsv_cmap_gradient('+tomato','lightblue', name='3.')
cmu.stitch_cmap ('plasma','viridis','inferno',bndry=[0.2,0.6], name='4.')
cmu.stitch_color ('red','yellow','green','blue',bndry=[0.3,0.4,0.8], name='5.')
cmu.binary_cmap ('red','blue', name='6.')
cmu.reversed_cmap ('viridis', name='7.')
cmu.mirrored_cmap ('viridis', name='8.')
cmu.alpha_cmap ('viridis',0.75, name='9.')
cmu.op_alpha_cmap ('viridis',lambda t:np.cos(2*np.pi*t), name='10.' )
cmu.op_cmap (RYGCBM,False, name='11.')
cmu.section_cmap ('viridis',0.2,0.8, name='12.')
cmx.Lab_cmap_gradient('red','blue', name='13.')
cmx.Hue_Lab_gradient ('red', name='14.')
cmx.Cmap_Lab_gradient('gist_rainbow_r', hiL=0.7, name='15.')
cmaps = [ str(i)+'.' for i in range(1,16)]