如何在R中生成一组最独特的颜色?

197

我正在绘制一个分类数据集,并希望使用独特的颜色来表示不同的类别。给定一个数字n,如何在R中获取n个最具有区分性的颜色?谢谢。


1
相关链接:https://dev59.com/pW025IYBdhLWcg3wVkUR#6076605 - Ben Bolker
1
相关:https://dev59.com/Umkw5IYBdhLWcg3w6ewb#41230685 - Kevin Wright
11个回答

175

我使用了RColorBrewer包中的所有定性调色板。定性调色板应该提供X种最独特的颜色。当然,混合它们会形成一个调色板,也会有相似的颜色,但这是我能得到的最好的结果(74种颜色)。

library(RColorBrewer)
n <- 60
qual_col_pals = brewer.pal.info[brewer.pal.info$category == 'qual',]
col_vector = unlist(mapply(brewer.pal, qual_col_pals$maxcolors, rownames(qual_col_pals)))
pie(rep(1,n), col=sample(col_vector, n))

colour_Brewer_qual_60

另一种解决方案是:从图形设备中获取所有R颜色并从中进行采样。我删除了灰色的阴影,因为它们太相似了。这样可以得到433种颜色。

color = grDevices::colors()[grep('gr(a|e)y', grDevices::colors(), invert = T)]

set of 20 colours

pie(rep(1,n), col=sample(color, n))

有200种颜色 n = 200

pie(rep(1,n), col=sample(color, n))

set of 200 colours


有没有可能将col中的十六进制代码转换为相应的颜色名称? - Prradep
@Prradep,你指的是哪个“col”?图形设备中的“color”有名称。如果你是指一般情况,不是所有的十六进制代码都有对应的颜色名称(在“grDevices”中只有433种颜色,但有更多的十六进制代码)。 - JelenaČuklina
我在你的代码片段中提到了RColorBrewer包中的col=sample(col_vector, n)。例如,如何找到#B3E2CD、#E78AC3、#B3DE69这些颜色对应的名称,可以使用sample(col_vector,3)。或者,如何使用brewer.pal函数找到所有十六进制代码及其颜色名称。 - Prradep
2
@Prradep,由于RColorBrewer调色板不是从具有名称映射的grDevices颜色派生而来,而只是十六进制代码,据我所知,您无法使用RColorBrewer调色板进行此操作,即使是定性的。 - JelenaČuklina
n接近4000时怎么办? - ytu
1
如果使用@ytu,那么颜色是无法区分的。如有必要,建议在R中寻找“渐变创建”,然后使用随机取样的颜色。但是将颜色映射到因子上是行不通的,人类感知只能处理大约20-40种颜色,其余的差别不是很大。 - JelenaČuklina

98

这里有几个选项:

  1. Have a look at the palette function:

     palette(rainbow(6))     # six color rainbow
     (palette(gray(seq(0,.9,len = 25)))) #grey scale
    
  2. And the colorRampPalette function:

     ##Move from blue to red in four colours
     colorRampPalette(c("blue", "red"))( 4) 
    
  3. Look at the RColorBrewer package (and website). If you want diverging colours, then select diverging on the site. For example,

     library(RColorBrewer)
     brewer.pal(7, "BrBG")
    
  4. The I want hue web site gives lots of nice palettes. Again, just select the palette that you need. For example, you can get the rgb colours from the site and make your own palette:

     palette(c(rgb(170,93,152, maxColorValue=255),
         rgb(103,143,57, maxColorValue=255),
         rgb(196,95,46, maxColorValue=255),
         rgb(79,134,165, maxColorValue=255),
         rgb(205,71,103, maxColorValue=255),
         rgb(203,77,202, maxColorValue=255),
         rgb(115,113,206, maxColorValue=255)))
    

谢谢你的回答。它生成了颜色,但有些颜色彼此之间不够明显。也许我在问题中应该更加强调这一点。 - RNA
1
@ RNAer 我已更新我的答案。你可以使用建议3和4来获得分歧调色板。 - csgillespie
1
"I want hue" 是一个很棒的网站。这正是我想要的。给定一个数字,如何生成相应数量的颜色调色板。但我们能否在 R 中自动完成呢? - RNA
这很棒。然而,这个网站背后有很多机制。我认为重新实现它不会是一件轻松的事情。如果“i want hue”有一个API可以自动查询就好了(也许它有——我没有花太长时间去找)。 - Ben Bolker
(@BenBolker - 尽管在 HCL 空间中的子集不太正确。) - jbaums

66

您还可以尝试使用randomcoloR软件包

library(randomcoloR)
n <- 20
palette <- distinctColorPalette(n)

您可以看到,在饼图中进行可视化时选择了一组高度不同的颜色(正如其他答案所建议的):

pie(rep(1, n), col=palette)

图片描述

用50种颜色在饼图中展示:

n <- 50
palette <- distinctColorPalette(n)
pie(rep(1, n), col=palette)

输入图像描述


7
谢谢。我需要使用 unname(distinctColorPalette(n)),才能使其与ggplot搭配使用。我猜测ggplot需要一个未命名的向量。col_vector <- unname(distinctColorPalette(n)),然后 ... + scale_color_manual(values=col_vector) ... - Gaurav

25

虽然这不是回答OP问题的答案,但值得一提的是有一个viridis软件包可以用于顺序数据的配色。它们在感知上是均匀的、对色盲者安全和友好打印的。

要获取颜色板,只需安装该软件包并使用viridis_pal()函数即可。有四个选项"A"、"B"、"C"和"D"可供选择。

install.packages("viridis")
library(viridis)
viridis_pal(option = "D")(n)  # n = number of colors seeked

此处输入图片描述

此处输入图片描述

此处输入图片描述

此外,YouTube 上也有一次关于好的色图复杂性的非常棒的演讲:

Matplotlib 的更佳默认色图 | SciPy 2015 | Nathaniel Smith 和 Stéfan van der Walt


28
这对于独特的颜色不太适合。 - Christopher John

15

您可以使用基础包或RColorBrewer软件包中的colorRampPalette函数:

使用colorRampPalette,您可以按照以下方式指定颜色:

colorRampPalette(c("red", "green"))(5)
# [1] "#FF0000" "#BF3F00" "#7F7F00" "#3FBF00" "#00FF00"

您也可以提供十六进制代码:

colorRampPalette(c("#3794bf", "#FFFFFF", "#df8640"))(5)
# [1] "#3794BF" "#9BC9DF" "#FFFFFF" "#EFC29F" "#DF8640"
# Note that the mid color is the mid value...

使用 RColorBrewer 你可以使用预定义的调色板颜色:

require(RColorBrewer)
brewer.pal(9, "Set1")
# [1] "#E41A1C" "#377EB8" "#4DAF4A" "#984EA3" "#FF7F00" "#FFFF33" "#A65628" "#F781BF"
# [9] "#999999"

查看RColorBrewer软件包以获取其他可用调色板。希望这有所帮助。


1
谢谢。我喜欢最后一个选项brewer.pal,但它只限于9种颜色。实际上我有超过9个类别。第一种替代方案生成渐变颜色,不如我想要的那么独特。 - RNA
2
你可能无法选择太多“不同”的颜色。我想最多只能有12种。你应该查看http://colorbrewer2.org/并获取颜色(如果我没记错的话,那里有1个12种颜色的调色板)。 - Arun
寻找超过12种独特的颜色可能会很困难 - 我认为在colorbrewer页面上有相关讨论。 - alexwhan
只要它们是可用的“最”独特的颜色,即使数字增加时它们变得不那么独特,也可以使用。 - RNA
3
如果您的问题是当相邻类别被指定为相似颜色时(如彩虹调色板所做的那样),那么您可以通过类似以下方式随机输出彩虹颜色来解决这个问题: rainbow(n=10)[sample(10)]。 - David Roberts

13

我建议使用外部资源来获取大型颜色调色板。

http://tools.medialab.sciences-po.fr/iwanthue/

提供了一项服务,可以根据各种参数组合任意大小的调色板。

https://graphicdesign.stackexchange.com/questions/3682/where-can-i-find-a-large-palette-set-of-contrasting-colors-for-coloring-many-d/3815

从图形设计师的角度讨论通用问题,并给出了可用调色板的许多示例。

要从RGB值中构建调色板,只需将这些值复制到向量中,例如:

colors37 = c("#466791","#60bf37","#953ada","#4fbe6c","#ce49d3","#a7b43d","#5a51dc","#d49f36","#552095","#507f2d","#db37aa","#84b67c","#a06fda","#df462a","#5b83db","#c76c2d","#4f49a3","#82702d","#dd6bbb","#334c22","#d83979","#55baad","#dc4555","#62aad3","#8c3025","#417d61","#862977","#bba672","#403367","#da8a6d","#a79cd4","#71482c","#c689d0","#6b2940","#d593a7","#895c8b","#bd5975")

10
你可以使用 Polychrome 包来实现此目的。它只需要颜色数和几个 seedcolors。例如:
# install.packages("Polychrome")
library(Polychrome)

# create your own color palette based on `seedcolors`
P36 = createPalette(36,  c("#ff0000", "#00ff00", "#0000ff"))
swatch(P36)

您可以在https://www.jstatsoft.org/article/view/v090c01了解更多关于这个软件包的内容。


Polychrome 看起来很有趣,但似乎没有更新以支持使用 R v4。 - Ian
固定的代码:先下载再安装scatterplot3d包,然后安装Polychrome_1.3.1.tar.gz包(路径为C:\...\),使用type="source"参数。 - Ian

9

我发现一个网站提供了20种独特的颜色列表:https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/

col_vector<-c('#e6194b', '#3cb44b', '#ffe119', '#4363d8', '#f58231', '#911eb4', '#46f0f0', '#f032e6', '#bcf60c', '#fabebe', '#008080', '#e6beff', '#9a6324', '#fffac8', '#800000', '#aaffc3', '#808000', '#ffd8b1', '#000075', '#808080', '#ffffff', '#000000')

你可以试一试!

4
这并没有回答问题,问题是如何生成n个不同的颜色,而不是一组已定义好的颜色。请尝试更新您的答案。 - Michal

3
你可以像这样生成一组颜色:

最初的回答:

你可以使用以下代码生成一组颜色:
myCol = c("pink1", "violet", "mediumpurple1", "slateblue1", "purple", "purple3",
          "turquoise2", "skyblue", "steelblue", "blue2", "navyblue",
          "orange", "tomato", "coral2", "palevioletred", "violetred", "red2",
          "springgreen2", "yellowgreen", "palegreen4",
          "wheat2", "tan", "tan2", "tan3", "brown",
          "grey70", "grey50", "grey30")

这些颜色尽可能地独特。对于那些相似的颜色,它们形成了一个渐变,以便您可以轻松地区分它们之间的差异。

最初的回答

3
在我的理解中,搜索独特的颜色与从一个单位立方体中高效地搜索相关,其中立方体的三个维度是沿着红、绿和蓝轴的三个向量。这可以简化为在一个圆柱体中搜索(HSV类比),其中你固定饱和度(S)和亮度(V),并找到随机的色相值。在许多情况下它是有效的,可以在这里看到:

https://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/

在R中,
get_distinct_hues <- function(ncolor,s=0.5,v=0.95,seed=40) {
  golden_ratio_conjugate <- 0.618033988749895
  set.seed(seed)
  h <- runif(1)
  H <- vector("numeric",ncolor)
  for(i in seq_len(ncolor)) {
    h <- (h + golden_ratio_conjugate) %% 1
    H[i] <- h
  }
  hsv(H,s=s,v=v)
}

另一种方法是使用R包“uniformly”,链接为https://cran.r-project.org/web/packages/uniformly/index.html。这个简单的函数可以生成独特的颜色:
get_random_distinct_colors <- function(ncolor,seed = 100) {
  require(uniformly)
  set.seed(seed)
  rgb_mat <- runif_in_cube(n=ncolor,d=3,O=rep(0.5,3),r=0.5)
  rgb(r=rgb_mat[,1],g=rgb_mat[,2],b=rgb_mat[,3])
}

可以通过网格搜索来考虑一些更复杂的函数:
get_random_grid_colors <- function(ncolor,seed = 100) {
  require(uniformly)
  set.seed(seed)
  ngrid <- ceiling(ncolor^(1/3))
  x <- seq(0,1,length=ngrid+1)[1:ngrid]
  dx <- (x[2] - x[1])/2
  x <- x + dx
  origins <- expand.grid(x,x,x)
  nbox <- nrow(origins) 
  RGB <- vector("numeric",nbox)
  for(i in seq_len(nbox)) {
    rgb <- runif_in_cube(n=1,d=3,O=as.numeric(origins[i,]),r=dx)
    RGB[i] <- rgb(rgb[1,1],rgb[1,2],rgb[1,3])
  }
  index <- sample(seq(1,nbox),ncolor)
  RGB[index]
} 

请检查这些功能的方法:
ncolor <- 20
barplot(rep(1,ncolor),col=get_distinct_hues(ncolor))          # approach 1
barplot(rep(1,ncolor),col=get_random_distinct_colors(ncolor)) # approach 2
barplot(rep(1,ncolor),col=get_random_grid_colors(ncolor))     # approach 3

然而,请注意,定义具有人类可感知颜色的独特调色板并不简单。哪种方法能够生成多样的颜色集尚未得到测试。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接