【问题标题】:Check or replace the value for the argument "palette" in the function ggplot2::discrete_scale()?检查或替换函数 ggplot2::discrete_scale() 中参数“调色板”的值?
【发布时间】:2019-10-01 20:23:39
【问题描述】:

在此之前,我想为我糟糕的英语道歉......

我定义了命名的自定义调色板,并希望在使用函数 ggplot() 创建绘图时使用自创函数轻松调用它们。因此我编写了一个只需要 3 个参数的“scale_function()”:

type       (character. "color" or "fill" for aesthetic mapping)

palette    (character. Name of an available palette)

discrete   (logical. TRUE for discrete data and FALSE for continuous data)

借助第二个函数,我使用 (grDevices::)colorRampPalette() 插入调色板的给定颜色。

到目前为止,一切都按计划进行。现在我在使用我的函数时注意到了一个非常具体的问题:

假设我们想要创建一个绘图,我们需要的颜色 (n) 比我选择的调色板 (c) 实际需要的颜色少。这意味着 n

palette_catalog 是一个列表,“palette_x”包括 6 种不同的颜色作为十六进制代码

palette_catalog[["palette_x"]]
# [1] "#d11141" "#00b159" "#00aedb" "#f37735" "#ffc425" "#cccccc"

情节

test <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

现在,如果我在情节“测试”中检查所选颜色,我检测到以下问题:

已正确使用已定义调色板的第一个和最后一个颜色(十六进制代码),但由于使用了 colorRampPalette,中间的颜色将被插值...因此初始十六进制代码被插值覆盖, 新的十六进制代码。 --> 那是主要问题!为了保持一致性, ggplot2::discrete_scale() 不应该那样做......

如果绘图需要的颜色多于调色板必须提供的颜色 (n > c),则结果绝对正确,但我想在 n

palette_catalog <- list(
  palette_x = c(
    "#d11141" (first value),
    "#00b159",
    "#00aedb",
    "#f37735",
    "#ffc425",
    "#cccccc" (last value)
  )
)

简而言之:如果情节需要,例如3个颜色值然后我希望discrete_scale()选择“palette_x”的第一个、第二个和第三个值,而不是第一个、插值的中间值和最后一个值...

我真的很抱歉我的英语混乱,我已经尽力描述我的问题,希望你能理解我的意思......

############## 一些应该可以工作的代码(减少到最低限度),只需将粘贴复制到您的 RStudio
palette_catalog <- list(
  palette_x = c(
    "#d11141",
    "#00b159",
    "#00aedb",
    "#f37735",
    "#ffc425",
    "#cccccc"
  )
)


interpolate <- function(palette = "palette_x", ...) {
  x <- palette_catalog[[palette]]
  colorRampPalette(x, ...)
}

scale_function <- function(
    type = "color",
    palette = "palette_x",
    discrete = TRUE,
    ...) {

  count <- length(palette_catalog[[palette]])
  pal <- interpolate(palette)

  if(type == "color") {    
    if(discrete) {
      discrete_scale("color", palette, palette = pal, ...)
    } else {
      scale_color_gradientn(colors = pal(count), ...)
    }
  }
}


### use this code on this standard plot with iris dataset:

ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

## you can print the used colors of a plot with the following code:
plot <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
  geom_point() +
  scale_function(palette = "palette_x")

gg <- ggplot_build(plot)

unique(gg$data[[1]]["colour"])
#      colour
# 1   #D11141
# 51  #799288
# 101 #CCCCCC

用于 3 个不同物种的预期(必需)颜色:

“palette_x”的前三个颜色值按顺序排列:

"#d11141",
"#00b159",
"#00aedb"

用于绘图的实际颜色不正确:

正如一开始已经提到的,情节使用了第一个、中间(插值)和最后一个颜色值...

"#d11141",
"#799288",
"#cccccc

如您所见,第二个颜色值无效,因为它是插值的结果,与“palette_x”的实际第二个值不匹配,应该是“#00b159”。

此外,第三个颜色值也是未请求的。相反,应该选择实际的第三个值,即“#00aedb”。

我真的希望有人可以帮助我并找到解决方案!我确定有一个。

我尝试了几种解决方案,但都没有奏效......

正如我已经说过的,代码运行良好。只是这个微小的具体案例让人头疼,此时 R 让我发疯......因为没有什么能像我预期的那样工作......

感谢您的帮助和支持!

【问题讨论】:

    标签: r ggplot2 colors


    【解决方案1】:

    我认为以下内容将为您提供我认为您正在寻找的大致内容。我们只需在函数中编写一个新函数,当 n

    scale_function <- function(type = "color", palette = "palette_x", discrete = TRUE, ...) {
    
      pal <- interpolate(palette)
    
      palfun <- function(n) {
        if (n > length(palette_catalog[[palette]])) {
          return(pal(n))
        } else {
          return(palette_catalog[[palette]][seq_len(n)])
        }
      }
    
      if(type == "color") {    
        if(discrete) {
          discrete_scale("color", palette, 
                         palette = palfun, 
                         ...)
        } else {
          scale_color_gradientn(colors = pal(count), ...)
        }
      }
    }
    

    您的示例现在将如下所示:

    g <- ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
      geom_point() +
      scale_function(palette = "palette_x")
    g
    

    有以下颜色:

    unique(layer_data(g)[["colour"]])
    
    [1] "#d11141" "#00b159" "#00aedb"
    

    如果你超过了调色板中的颜色数量,它应该开始插值:

    df <- iris
    # Random discrete variable
    df$catvar <- sample(LETTERS[1:10], size = 150, replace = T)
    
    g2 <- ggplot(df, aes(Sepal.Width, Sepal.Length, color = catvar)) +
      geom_point() +
      scale_function(palette = "palette_x")
    

    unique(layer_data(g2)[["colour"]]) # Not in right order due to random sampling
    
     [1] "#FDBB26" "#00B067" "#BC8359" "#00AFAF" "#E8C76F" "#CCCCCC" "#D11141" "#F6902F" "#5C694E" "#35A1B6"
    

    【讨论】:

    • 非常感谢您的解决方案!我立即实现了 palfun(),但是如果我执行 ggplot(iris, ...),我会收到一条奇怪的警告消息:“警告消息:删除了 150 行包含缺失值 (geom_point)。”它会显示仅带有轴和标签但没有任何几何美学或颜色的空图...为什么我会收到此警告?这是什么意思?
    • 函数返回的颜色很可能是 NA,这会给出错误消息。我已经在另一台计算机上重新运行了代码,但它不会为我抛出任何错误消息。你确定你在 scale_function() 内部而不是外部实现了 palfun() 吗?
    • 我还使用此处发布的代码摘录重新运行了代码。它确实有效!但是在我稍微扩展的原始版本中,出现了上述警告消息......所以我的附加代码中有问题引发了这个警告......是的,我确实在我的 scale_function 中实现了 palfun() ......是否有可能与您共享(或发送)我的整个代码?我应该把它贴在这里作为答案吗?对不起,愚蠢的问题,我是菜鸟......
    • 没关系!我确定了问题的根源。我不得不 unname() 我个人的命名列表组件。对于每个调色板,我还命名了调色板中的每种颜色。例如:base_colors &lt;- c( "midnight" = "#000000, ...) and then palette_catalog &lt;- list( palette_x = base_colors[1:n] ) 所以这个简单的更改对我有用:palfun &lt;- function(n) { if (n &gt; length(palette_catalog[[palette]])) { return(pal(n)) } else { return(unname(palette_catalog[[palette]][seq_len(n)])) } }
    • 再次感谢您的支持!我真的很感激。
    【解决方案2】:

    请原谅我的误会,但我相信你仍然可以使用colorRampPalette(),但是作为一个函数:

    pal_domains <- brewer.pal(name = "Set3", n = 12)
    pal_function <- colorRampPalette(pal_domains)
    
    
    ggplot(iris, aes(Sepal.Width, Sepal.Length, color = Species)) +
      geom_point() +
      scale_color_manual(values = pal_function(3))
    
    
    

    您可以将pal_function() 与任意数量的值一起使用,并根据需要更改调色板名称。

    【讨论】:

    • 没问题,请随意将其标记为正确 :) 祝你好运!
    猜你喜欢
    • 2021-05-08
    • 2021-10-18
    • 2021-06-13
    • 2013-02-18
    • 2014-10-23
    • 2012-09-02
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    相关资源
    最近更新 更多