R:使用ggplot2和marrangeGrob

时间:2016-12-16 20:26:53

标签: r ggplot2 gridextra

我需要在研究中为各种受试者制作大量的药物浓度图,并且我希望根据他们服用的药物一致地设定颜色。但并非所有患者都服用相同的药物。这是我尝试过的:

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]],前两个图将至少生成图(尽管每种药的颜色不一致)而不是我指定的那个),但第三个是给我一个关于没有足够值的错误的那个。

这是第一个情节,咪达唑仑的颜色正确:concentration time curve midazolam

这是第二个情节,没有正确的颜色:concentration time curve midazolam dextromethorphan

这里发生了什么?为什么这不起作用?

1 个答案:

答案 0 :(得分:1)

为什么这不起作用?

情节3是问题 - 不是单独的,而是与for循环和ggplot2的懒惰评估机制相结合。当您定义每个图时,ggplot2正确捕获第i个数据集的环境,但手动比例存储为未评估的承诺。当它最终被评估时(在绘制之前不久调用ggplot_build),MyColors.temp只有两个值(循环的最新迭代),而图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)

enter image description here

磨制

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)

enter image description here

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

分割申请

如果您需要单独的图表,使用长格式data.frame,

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

grid.arrange(grobs = lp)

enter image description here