使用scale_color_gradientn在ggplot2中生成的图表列表颜色错误

3
我尝试使用library(scales)scale_color_gradientn()来创建颜色到连续变量的自定义映射,以限制异常值对我的图形着色的影响。这对单个图形有效,但是当我使用循环生成多个图形并将它们存储在列表中时,却不起作用。
这是一个最小化的工作示例:
library(ggplot2)
library(scales)

data1 <- as.data.frame(cbind(x = rnorm(100),
                             y = rnorm(100),
                             v1 = rnorm(100, mean = 2, sd = 1),
                             v2 = rnorm(100, mean = -2, sd = 1)))

#add outliers
data1[1,"v1"] <- 200
data1[2,"v1"] <- -200
data1[1,"v2"] <- 50
data1[2,"v2"] <- -50

#define color palette
cols <- colorRampPalette(c("#3540FF","black","#FF3535"))(n = 100)

#simple color scale
col2 <- scale_color_gradient2(low = "#3540FF",
                              mid = "black",
                              high = "#FF3535"
                              )

#outlier-adjusted color scale
{
    aa <- min(data1$v1)
    bb <- quantile(data1$v1, 0.05)
    cc <- quantile(data1$v1, 0.95)
    dd <- max(data1$v1)

    coln <- scale_color_gradientn(colors = cols[c(1,5,95,100)],
               values = rescale(c(aa,bb,cc,dd),
                    limits = c(aa,dd))
                                                                 )
}

情节:

1. 使用简单刻度的图表 - 异常值会导致刻度拉伸。

ggplot(data1, aes(x = x, y = y, color = v1))+
   geom_point()+
   col2

使用调整后的刻度进行绘图 - 正确的颜色比例尺

2. 使用调整后的比例尺绘图 - 正确的颜色比例尺。

ggplot(data1, aes(x = x, y = y, color = v1))+
    geom_point()+
    coln

校正异常值刻度的图表-正确的颜色比例

3. v1的刻度不适用于v2,因为数据不同。

ggplot(data1, aes(x = x, y = y, color = v2))+
    geom_point()+
    coln

The scales for v1 do not work for v2 as the data is different

#loop to produce list of plots each with own scale
{
    plots <- list()
    k <- 1
    for (i in c("v1","v2")){
        aa <- min(data1[,i])
        bb <- quantile(data1[,i],0.05)
        cc <- quantile(data1[,i], 0.95)
        dd <- max(data1[,i])

        colm <- scale_color_gradientn(colors = cols[c(1,5,95,100)],
                     values = rescale(c(aa,bb,cc,dd),
                         limits = c(aa,dd)))

        plots[[k]] <- ggplot(data1, aes_string(x = "x",
                                               y = "y",
                                                   color = i
                                                   ))+
                     geom_point()+
                     colm

        k <- k + 1
    }
}

4. 第一个图的刻度有误。

plots[[1]]

第一张图的比例尺有误

5. 第二张图的比例尺正确。

plots[[2]]

第二张图的比例尺是正确的

所以我猜这可能与在绘图时调用scale_color_gradientn()函数有关,而不是在循环内部调用。

如果有人能帮助解决这个问题,将不胜感激。在基础R中,我会对连续数据进行分组,并将十六进制颜色分配到用于填充颜色的向量中,但我不确定如何在ggplot中应用它。

1个回答

1
你需要使用一个闭包(带有关联环境的函数):
{
  plots <- list()
  k <- 1
  for (i in c("v1", "v2")){
    colm <- function() {
      aa <- min(data1[, i])
      bb <- quantile(data1[, i], 0.05)
      cc <- quantile(data1[, i], 0.95)
      dd <- max(data1[, i])

      scale_color_gradientn(colors = cols[c(1, 5, 95, 100)],
                            values = rescale(c(aa, bb, cc, dd),
                            limits = c(aa, dd)))
    }

    plots[[k]] <- ggplot(data1, aes_string(x = "x",
                                           y = "y",
                                           color = i)) +
                    geom_point() +
                    colm()
    k <- k + 1
  }
}

plots[[1]]

enter image description here

plots[[2]]

enter image description here


谢谢你的回答。 我的理解是,我的例子不起作用的原因是在绘图时调用了一个函数(我认为这是对象colm中的一个函数?),该函数访问了来自该环境中aabbccdd的最后一个值。这里我的理解正确吗?我想我不太明白为什么i成功传递到ggplot()函数,而计算出的aa等值没有传递。这是否与ggplot()返回类型与scale_color_gradientn()返回类型有关? - Duncan Murray
ggplot() + ... 结构的不同部分在不同的时间被评估(初始构建与绘图时)。在您编写的代码中,当您调用 plot [[1]] 时,scale_color_gradientn() 的参数仅在该时间被评估,并且此时 aabb 等的内容对应于最后一个图。在 R 中,您永远无法确定函数将在何时在哪个环境中进行评估。这就是为什么闭包是这些编码场景的通用方法的原因。 - Claus Wilke
太棒了,那非常有道理。再次感谢。 - Duncan Murray

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