使用 cowplot 拼凑图时颜色渐变不正确

Posted

技术标签:

【中文标题】使用 cowplot 拼凑图时颜色渐变不正确【英文标题】:Incorrect colour gradient when using cowplot to patch together plots 【发布时间】:2019-09-07 19:16:57 【问题描述】:

假设我有一个数据集,其中包含根据两个变量分组的 xy 值:grpabc,而 subgrp 是 @987654335 @、FG

a 在 [0, 1] 中有 yb 在 [10, 11] 中有 yc 在 [100, 101] 中有 y 值。

我想用y 为所有grpsubgrp 组合定义的点颜色绘制yx。由于每个grp 具有非常不同的y 值,因此我不能单独使用facet_grid,因为色标将毫无用处。所以,我用自己的比例绘制每个grp,然后将它们与来自cowplotplot_grid 一起修补。我还想使用scale_colour_gradient2 指定的三点渐变。我的代码如下所示:

# Set RNG seed
set.seed(42)

# Toy data frame
df <- data.frame(x = runif(270), y = runif(270) + rep(c(0, 10, 100), each = 90),
                 grp = rep(letters[1:3], each = 90), subgrp = rep(LETTERS[4:6], 90))

head(df)
#>           x         y grp subgrp
#> 1 0.9148060 0.1362958   a      D
#> 2 0.9370754 0.7853494   a      E
#> 3 0.2861395 0.4533034   a      F
#> 4 0.8304476 0.1357424   a      D
#> 5 0.6417455 0.8852210   a      E
#> 6 0.5190959 0.3367135   a      F

# Load libraries
library(cowplot)
library(ggplot2)
library(dplyr)

# Plotting list
g_list <- list()

# Loop through groups 'grp'
for(i in levels(df$grp))
  # Subset the data
  df_subset <- df %>% filter(grp == i)
  
  # Calculate the midpoint
  mp <- mean(df_subset$y)
  
  # Print midpoint
  message("Midpoint: ", mp)
  
  g <- ggplot(df_subset) + geom_point(aes(x = x, y = y, colour = y))
  g <- g + facet_grid(. ~ subgrp) + ggtitle(i)
  g <- g + scale_colour_gradient2(low = "blue", high = "red", mid = "yellow", midpoint = mp)
  g_list[[i]] <- g

#> Midpoint: 0.460748857570191
#> Midpoint: 10.4696476330981
#> Midpoint: 100.471083269571

plot_grid(plotlist = g_list, ncol = 1)

由reprex package (v0.2.1) 于 2019 年 4 月 17 日创建

在这段代码中,我将颜色渐变的中点指定为每个grpy 的平均值。我打印并验证它是否正确。是的。

我的问题:为什么前两个图的色阶不正确?

尽管对数据进行了子集化,但似乎对每个 grp 应用了相同的范围。如果我将for(i in levels(df$grp)) 替换为for(i in levels(df$grp)[1]),则生成的单个图的色标是正确的。


更新

好吧,这很奇怪。在g_list[[i]] &lt;- g 之前插入ggplot_build(g)$data[[1]]$colour 可以解决问题。 但是,为什么?

【问题讨论】:

这通常会出现循环和ggplot2。我不确定您的确切情况,但这可能与在图中评估变量时有关。见解释here和信息here @aosmith 这真的很有趣。那么,大概ggplot_build(g)$data[[1]]$colour 强制评估并因此保留应有的颜色?似乎另一种选择是 print 不可见地块:invisible(print(g)) 就在 g_list[[i]] &lt;- g 之前。 这是我的猜测。我喜欢将数据集按组拆分为列表然后循环遍历数据集以使用lapply()/purrr::map() 制作许多 ggplot2 图的方法之一是它避免了一些这个。 @aosmith 好东西。我会试试的。感谢您的帮助。 我在循环和 ggplot 方面遇到过类似情况,答案是,ggplot 存在局部变量问题。我觉得这里有点像。仍然不确定为什么 ggplot 会这样。 my old question 【参考方案1】:

长话短说,您正在创建未经评估的承诺,然后在原始数据消失时对其进行评估。如果您使用正确的函数式编程风格而不是过程代码,则通常可以避免此问题。即,定义一个完成工作的函数,然后为循环使用一个应用函数。

set.seed(42)

# Toy data frame
df <- data.frame(x = runif(270), y = runif(270) + rep(c(0, 10, 100), each = 90),
                 grp = rep(letters[1:3], each = 90), subgrp = rep(LETTERS[4:6], 90))

library(cowplot)
library(ggplot2)
library(dplyr)

# Loop through groups 'grp'
g_list <- lapply(
  levels(df$grp), 
  function(i) 
    # Subset the data
    df_subset <- df %>% filter(grp == i)

    # Calculate the midpoint
    mp <- mean(df_subset$y)

    # Print midpoint
    message("Midpoint: ", mp)

    g <- ggplot(df_subset) + geom_point(aes(x = x, y = y, colour = y))
    g <- g + facet_grid(. ~ subgrp) + ggtitle(i)
    g <- g + scale_colour_gradient2(low = "blue", high = "red", mid = "yellow", midpoint = mp)
    g
  
)
#> Midpoint: 0.460748857570191
#> Midpoint: 10.4696476330981
#> Midpoint: 100.471083269571

plot_grid(plotlist = g_list, ncol = 1)

由reprex package (v0.2.1) 于 2019 年 4 月 17 日创建

【讨论】:

考虑by,比嵌套的lapply + splitlapply + levelslapply + unique 更精简。

以上是关于使用 cowplot 拼凑图时颜色渐变不正确的主要内容,如果未能解决你的问题,请参考以下文章

div背景颜色怎样渐变 css实现div层背景颜色渐变代码

如何用css使边框颜色渐变

html中想要将背景颜色渐变怎么弄?

用css的方法达到边框颜色渐变,最好支持chrome

使用div+css实现背景颜色渐变,怎么实现呢?

css 如何实现 颜色的渐变??