R:使用 ggplot2 和 marrangeGrob 为多个图设置颜色时出错

R: Error when setting colors for multiple plots using ggplot2 and marrangeGrob

我需要为研究中的不同受试者在一段时间内绘制大量药物浓度图,并且我想根据他们服用的药物始终如一地设置颜色。不过,并非所有患者都服用相同的药物。这是我尝试过的:

library(plyr)
library(ggplot2)
library(gridExtra)

A <- data.frame(Time = seq(0, 20, 5),
            DrugConcentration = 100*exp(-0.25*seq(0, 20, 5)),
            Drug = "Midazolam")

B <- data.frame(Time = rep(seq(0, 20, 5), 2),
                DrugConcentration = c(100*exp(-0.25*seq(0, 20, 5)),
                                      75*exp(-0.1*seq(0, 20, 5))),
                Drug = rep(c("Midazolam", "Dextromethorphan"), each = 5))

C <- data.frame(Time = rep(seq(0, 20, 5), 3),
                DrugConcentration = c(100*exp(-0.25*seq(0, 20, 5)),
                                      75*exp(-0.1*seq(0, 20, 5)),
                                      50*exp(-0.15*seq(0, 20, 5))),
                Drug = rep(c("Midazolam", "Dextromethorphan", "Tolbutamide"), 
                           each = 5))

D <- data.frame(Time = rep(seq(0, 20, 5), 2),
                DrugConcentration = c(100*exp(-0.25*seq(0, 20, 5)),
                                      50*exp(-0.15*seq(0, 20, 5))),
                Drug = rep(c("Midazolam", "Tolbutamide"), 
                           each = 5))

DrugList <- list(A, B, C, D)

MyColors <- data.frame(Drug = c("Midazolam", "Dextromethorphan", "Tolbutamide"),
                       Color = c("red", "green", "blue"),
                       stringsAsFactors = FALSE)

PlotList <- list()

for(i in 1:length(DrugList)){
      DrugList[[i]] <- arrange(DrugList[[i]], Drug, Time)
      MyColors.temp <- join(DrugList[[i]][, c("Drug", "Time")], 
                        MyColors, by = "Drug")
      MyColors.temp <- unique(MyColors.temp[, c("Drug", "Color")])
      MyColors.temp <- arrange(MyColors.temp, Drug)

      PlotList[[i]] <- 
          ggplot(DrugList[[i]], 
               aes(x = Time, y = DrugConcentration, 
                   color = Drug)) +
          geom_point() + geom_line() +
          scale_color_manual(values = MyColors.temp$Color)
}

循环运行,但是当我尝试

marrangeGrob(PlotList, nrow = 2, ncol = 2)

我收到错误:Insufficient values in manual scale. 3 needed but only 2 provided. 如果我单独查看每个图,例如,通过键入 PlotList[[1]],前两个图至少会生成图(尽管颜色不一致每种药物,而不是我指定的药物),但第三种药物给我带来了关于没有足够价值的错误。

这是第一个图,咪达唑仑的正确颜色是:

这是第二张图,颜色不正确:

这是怎么回事?为什么这不起作用?

为什么这不起作用?

图 3 是问题所在——不是它本身,而是与 for 循环和 ggplot2 的惰性求值机制相结合。当您定义每个绘图时,ggplot2 会正确捕获第 i 个数据集的环境,但手动比例存储为未评估的承诺。当它最终被评估时(当 ggplot_build 在绘图前不久被调用时),MyColors.temp 只有两个值(循环的最新迭代),并且 plot 3 抱怨手动比例提供的值太少.

为什么色阶不一致?

scale_colour_manual 需要一个命名向量,而不是一对值 - 中断(在我阅读帮助页面之前,它确实愚弄了我!)。

有几种可能的解决方案。

将整组颜色作为命名向量传递

MyColors <- c("Midazolam" = "red", "Dextromethorphan" = "green", "Tolbutamide" = "blue")

DrugList <- list(A, B, C, D)

PlotList <- list()

for(i in 1:length(DrugList)){

  PlotList[[i]] <- 
    ggplot(arrange(DrugList[[i]], Drug, Time), 
           aes(x = Time, y = DrugConcentration, 
               color = Drug)) +
    geom_point() + geom_line()  +
    scale_colour_manual(values = MyColors) +
    theme()
}

grid.arrange(grobs=PlotList)

刻面

m <- reshape2::melt(DrugList, measure.vars = "DrugConcentration")
str(m)

p <- ggplot(m, aes(x = Time, y = value, color = Drug)) +
  facet_wrap(~L1) +
  geom_point() + geom_line() +
  scale_colour_manual(values = MyColors)

ggforce 似乎提供了可以扩展到多个页面的构面功能。使用额外的虚拟变量将整个数据集分成组以绘制为单独的 2x2 面也很容易实现。

拆分应用

如果您需要单独的图,使用长格式也更容易 data.frame,

lp <- plyr::dlply(m, "L1", function(d) p %+% d)

grid.arrange(grobs = lp)