色彩 教程


色彩要注意区分度(还要注意色盲人士)和美观。

我们日常绘图主要使用R及R包,少量使用Python及其他工具。


日常看到各种漂亮的色彩组合,可以截图放到PPT中归类。

如果不确定,就试试色彩组合: "navy", "firebrick3"。


本站主题索引:

原生R中的颜色与渐变色。

R 色彩 详解与实例: SCI中的常见色彩组合,canvas 展示。

Python3 色彩 详解与实例: 在 python 中使用色彩。


颜色辅助工具


颜色模型 /color space

我们有限的语言(红橙黄绿蓝靛紫)只能明确定义某几个或几十个颜色,更多细微差别的颜色的描述就需要数字化了。所谓颜色模型就是描述颜色的数学模型,或者说颜色的数字形式及其意义。

R包colorspace 的 color-class 文档说: there are subclasses of color which correspond to RGB, HSV, HLS, CIEXYZ, CIELUV, CIELAB and polar versions of the last two spaces.

而 circlize 包的colorRamp2()文档说 color space in which colors are interpolated. Value should be one of "RGB", "HSV", "HLS", "LAB", "XYZ", "sRGB", "LUV",

RGB 颜色模型

最常见的RGB模型,也最符合人的直觉。它使用 红绿蓝 三原色的光强来描述颜色,比如 rgb(255,0,0) ,每种光线从0-255共256个强度,谁数值大就偏向谁,两个极端是黑(3个值都最小,没有任何光照)和白(三个光都最强,就是白日光)。R语言中 rgb() 函数默认是把光强标准化到0-1之间,也可以自己设定最大值,如 > rgb(255,0,0, maxColorValue = 255) #返回颜色 "#FF0000"。

16进制也是RGB颜色模型的最常用表示形式,它比rgb()函数更紧凑,更适合传输和存储,是各种编程语言都广泛接受的颜色表示形式。标准形式就是"#RRGGBB", #开头,后面rgb各2位的16进制形式。16进制的2位对应着十进制的0-255,两位分别用数字0-9和字母A-F表示,字母一般使用大写,很多小写也不报错。

alpha 不透明度

不透明度显著影响颜色的视觉效果。一般用16进制的7-8位表示alpha,范围是0-255。默认是不透明度最大(FF), 就是完全不透明。而最小值00则表示不透明度最小,就是完全透明。查看接近完全透明的红色 > plot(mtcars, col="#FF000011")。ggplot2中把alpha标准化到0-1之间。

CMYK 颜色模型

这是一个四色打印机颜色模型,和RGB类似,不过用了4个基础颜色。采用加法模型,没有颜色的时候是白色,谁数值大偏向谁,四个颜色都用且最大就是黑色。

HSL 颜色模型:符合人直觉

按照 色相hue, 饱和度saturation, 和明度lightness 定义颜色。

取值范围: hue[0,360], saturation[0, 100%], lightness[0, 100%]

色相hue, 也叫色别,不同颜色的表象和名称,如红、橙、黄、绿、青、蓝、紫等。不同的色别都可用光谱中的波长来标示,人的眼睛可分辨出的色别有180种左右。

明度, 色彩的明暗程度。一般在反光率相同的情况下,不同色别的明暗程度不同。如黄色光比红色光更明亮,而红色光则比青色光要明亮。明度最高是白色,明度适中是不同的彩色,明度最低则是黑色。

饱和度(纯度)是指同一色别的纯净度和鲜明度的变化。饱和度越高,颜色越鲜艳;饱和度越低,颜色越灰黑暗沉。

HSL取色1, HSL取色工具(本地版)

HSL和RGB的相互转化的 公式(点击查看)R代码实现 如下:

# specify h as whole input degrees (e.g 0-360) # s = 0.0 - 1 (0 - 100%) # l = 0.0 - 1, (0 - 100%) # returns output from R's rgb() functin hsl_to_rgb <- function(h, s, l) { h <- h / 360 r <- g <- b <- 0.0 if (s == 0) { r <- g <- b <- l } else { hue_to_rgb <- function(p, q, t) { if (t < 0) { t <- t + 1.0 } if (t > 1) { t <- t - 1.0 } if (t < 1/6) { return(p + (q - p) * 6.0 * t) } if (t < 1/2) { return(q) } if (t < 2/3) { return(p + ((q - p) * ((2/3) - t) * 6)) } return(p) } q <- ifelse(l < 0.5, l * (1.0 + s), l + s - (l*s)) p <- 2.0 * l - q r <- hue_to_rgb(p, q, h + 1/3) g <- hue_to_rgb(p, q, h) b <- hue_to_rgb(p, q, h - 1/3) } return(rgb(r,g,b)) } if(0){ cols=c() for(h in seq(0, 359, 60)){ cols=c(cols, hsl_to_rgb( h, 0.5, 0.5)) } cols |> jsonlite::toJSON() c("#8C7373","#8C8C73","#738C73","#738C8C","#73738C","#8C738C") #10% s c("#996666","#999966","#669966","#669999","#666699","#996699") #20% s c("#A65959","#A6A659","#59A659","#59A6A6","#5959A6","#A659A6") #30% s c("#B34D4D","#B2B34D","#4DB34D","#4DB2B3","#4D4DB3","#B34DB2") #40% s c("#BF4040","#BFBF40","#40BF40","#40BFBF","#4040BF","#BF40BF") #50% s c("#CC3333","#CCCC33","#33CC33","#33CCCC","#3333CC","#CC33CC") #60% s c("#D92626","#D9D926","#26D926","#26D9D9","#2626D9","#D926D9") #70% s c("#E61919","#E5E619","#19E619","#19E5E6","#1919E6","#E619E5") #80% s c("#F20D0D","#F2F20D","#0DF20D","#0DF2F2","#0D0DF2","#F20DF2") #90% s c("#FF0000","#FFFF00","#00FF00","#00FFFF","#0000FF","#FF00FF") #100% s # hsl_to_rgb( 180, 0.5, 0.5) "#40BFBF" hsl_to_rgb( 0, 0.315, 0.5) "#A85757" } if(0){ # 随机颜色 getColor=function(base_S=50, base_L=50){ random=function(){ runif(1, 0, 1) } hue = random() * 360 saturation = base_S + (random() * 20); lightness = base_L + (random() * 20); # hsl_to_rgb(hue, saturation/100, lightness/100) } getColor() c("#D53897", "#D66D6B", "#7FD0D9", "#C9D750") getColor(base_S=40) c("#C8559A", "#6F75D6", "#CD399E", "#7DD587") } # r, g, b = 0.0 - 1 (0 - 100%) # returns h/s/l in a vector, h = 0-360 deg, s = 0.0 - 1 (0-100%), l = 0.0 - 1 (0-100%) rgb_to_hsl <- function(r, g, b) { val_max <- max(c(r, g, b)) val_min <- min(c(r, g, b)) h <- s <- l <- (val_max + val_min) / 2 if (val_max == val_min){ h <- s <- 0 } else { d <- val_max - val_min s <- ifelse(l > 0.5, d / (2 - val_max - val_min), d / (val_max + val_min)) if (val_max == r) { h <- (g - b) / d + (ifelse(g < b, 6, 0)) } if (val_max == g) { h <- (b - r) / d + 2 } if (val_max == b) { h <- (r - g) / d + 4 } h <- (h / 6) * 360 } return(c(h=h, s=s, l=l)) } if(0){ my.col=(col2rgb("#FFaabb")/255) |> as.vector(); my.col rgb_to_hsl(my.col[1], my.col[2], my.col[3]) hsl_to_rgb(348, 1, 0.83) "#FFA8BA" }

LAB 颜色模型

RGB 的优点是符合人的直觉,缺点是不符合人的直觉。听起来很矛盾,就是你感觉该这样,但可能太亮或太暗,不肉眼查看你无法确定你选择的一组颜色是否区分度好且美观协调。

Lab模式既不依赖光线,也不依赖于颜料,它是CIE组织确定的一个理论上包括了人眼可以看见的所有色彩的色彩模式。Lab模式弥补了RGB和CMYK两种色彩模式的不足。同RGB颜色空间相比,Lab是一种不常用的色彩空间。它是在1931年国际照明委员会(CIE)制定的颜色度量国际标准的基础上建立起来的。1976年,经修改后被正式命名为CIELab。它是一种设备无关的颜色系统,也是一种基于生理特征的颜色系统。这也就意味着,它是用数字化的方法来描述人的视觉感应。

Lab颜色空间比计算机显示器甚至比人类视觉的色域都要大。Lab颜色模型由三个要素组成,一个要素是亮度(L),a 和b是两个颜色通道。 More1>> | 更多1>>.

理论上说,L*、a*、b*都是实数,不过实际一般限定在一个整数范围内:
- L越大,亮度越高。L为0时代表黑色,为100时代表白色。
- a和b为0时都代表灰色。
- a从负数变到正数,对应颜色从绿色变到红色。从深绿色(低亮度值)到灰色(中亮度值)再到亮粉红色(高亮度值);
- b从负数变到正数,对应颜色从蓝色变到黄色。从亮蓝色(低亮度值)到灰色(中亮度值)再到黄色(高亮度值)。

- 我们在实际应用中常常将颜色通道的范围-100~+100或-128~127之间。

参考资料

http://www.cookbook-r.com/Graphs/Colors_(ggplot2)/
http://www.sthda.com/english/wiki/ggplot2-colors-how-to-change-colors-automatically-and-manually
https://github.com/DawnEve/ImmunogenomicLandscape-BloodCancers/blob/master/common_scripts/visualisation/plotting_functions.R