在循环中的ggplot中生成一致的动态调色板?

mat*_*ier 8 r ggplot2

我有一个名为d1的数据集类似于:

location, depth.from, depth.to, val, type 
Run Code Online (Sandbox Code Playgroud)

我有一个循环,为每个独特的位置创建一个相当复杂的绘图(它将许多东西粘在一起使用grid.arrange,这就是为什么我不能facet_wrap在该位置使用以保持图的一部分的图例/颜色一致).

假设"类型"有4个类别,当一个位置具有不同数量的"类型"而不是另一个位置时,所分配的颜色在每个图之间不一致.我可以手动强制它们是相同的,但我试图概括这个功能.谷歌让我失望了.

对于以下块,d1是基于位置类型的数据的子集,例如

d1 <- subset(myData, location == location.list[i])
Run Code Online (Sandbox Code Playgroud)

看一下循环内的情节:

p1 <- ggplot(data = d1, aes (y=val, x=depth.from))+
layer(geom = "point", size = 2) + 
geom_rect(data=d1, aes(xmin=Depth.to, xmax=Depth.from, ymin=0, ymax=100, fill = type), linetype =0, alpha=0.3)+
scale_fill_brewer(palette="Set1")
Run Code Online (Sandbox Code Playgroud)

geom_rect命令将通过数据并基于深度和深度来创建基于填充类型的叠加.我可以使用scale_fill_manual("Lith", c("Val1" = "DodgerBlue4"...)etc来手动设置它,但这会破坏目的.如果我有:类型喜欢我想要的东西:

Bird_one = blue
Bird_two = red
Bird_three = green
Run Code Online (Sandbox Code Playgroud)

我想bird_three成为绿色,即使bird_two不存在,也不必明确地使用它scale_fill_manual.有没有办法为调色板设置全局名称列表?也许通过以下方式提供数组:

myData <- read.csv("mydata.csv" 
typeList <- unique(myData$type)
Run Code Online (Sandbox Code Playgroud)

ale*_*han 6

它们是否处于循环中并不重要,您只需要将每个级别与颜色相关联即可.在你的情况下:

colourList <- c(bird_one = "red", bird_two = "blue", bird_three = "green")
Run Code Online (Sandbox Code Playgroud)

在一个简单的例子中:

#Make some data
dat <- data.frame(location = rep(1:4, c(3,2,2,3)), val = rnorm(10), 
  depth.from = sample(1:5, 10, replace = TRUE), depth.to = sample(6:10, 10, replace = TRUE),
  type = factor(LETTERS[c(1:3, 1,3,1,3,1:3)]))

#Associate levels with colours
colourList <- c(A = "red", B = "blue", C = "green")

p <- list()
for(i in 1:4) {
  d <- dat[dat$location == i,]
  p[[i]] <- ggplot(data = d, aes (y=val, x=depth.from))+
    layer(geom = "point", size = 2) + 
    geom_rect(aes(xmin=depth.to, xmax=depth.from, ymin=0, ymax=100, fill = type), linetype =0, alpha=0.3) +
    #This is where the assignment works
    scale_fill_manual(values=colourList)
}
grid.arrange(p[[1]], p[[2]])
Run Code Online (Sandbox Code Playgroud)

您可以C在两个图中看到该级别为绿色.

为了回应@BrodieG,这里有一种半自动设置颜色的方法.它使用typeRColorBrewer包中的级别和颜色值创建命名向量.这可以很容易地开发出来包含在一个函数中:

library(RColorBrewer)
colourList <- setNames(brewer.pal(length(levels(dat$type)), "Set1"), levels(dat$type))
Run Code Online (Sandbox Code Playgroud)

正如@hadley指出的那样,在这种情况下,设置比例限制更为直接,尽管在我的典型用法中我发现设置一个对象更有用colourList,可以通过设置在多个图中使用values.设置limits还会维护图例的级别,这可能是也可能不是想要的:

scale_fill_brewer(limits = levels(dat$type), palette = "Set1")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

正如@hadley指出的那样,在这种情况下,设置比例限制更为直接,尽管在我的典型用法中我发现设置一个对象更有用colourList,可以通过设置在多个图中使用values.设置limits还会维护图例的级别,这可能是也可能不是想要的:

scale_fill_brewer(limits = levels(dat$type), palette = "Set1")
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Bro*_*ieG 5

很晚,但实际上通过设置实现了一个简单的解决方案 scale_fill_discrete(drop=F)

plots <- lapply(dfs, function(df) {
  ggplot(df, 
    aes(
      x=location, fill=type, 
      y=(depth.from + depth.to) / 2, 
      ymin=depth.from, ymax=depth.to
  ) ) +
  geom_crossbar() + scale_fill_discrete(drop=F)
})
library(gridExtra)
do.call(grid.arrange, plots)
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这是我使用的虚拟数据:

set.seed(12)
items <- 2
dfs <- 
  replicate(2, simplify=F,
    data.frame(
      location=sample(letters, items), 
      depth.from=runif(items, -10, -5),
      depth.to=runif(items, 5, 10),
      val=runif(items),
      type=factor(
        sample(c("Bird_one", "Bird_two", "Bird_three"), items),
        levels=c("Bird_one", "Bird_two", "Bird_three")
  ) ) )
Run Code Online (Sandbox Code Playgroud)