自动检测自定义 ggplot2 中的离散或连续调色板

Ped*_*nda 4 r ggplot2

我正在开发一个名为ipeaplot主题和调色板标准化的包。我们所做的尝试之一是创建一个scale_color()能够区分用户传递的是连续列还是离散列的函数(例如,如果列类是数字或整数,则尺度选择应该是连续的,否则应该是离散的)

下面是代码示例

# Install package
remotes::install_github("ipeadata-lab/ipeaplot")
library(ggplot2)
library(ipeaplot)
Run Code Online (Sandbox Code Playgroud)

这段代码可以工作,但是请注意我必须指定我想要的是连续的比例

ggplot(data = mtcars, aes(x = mpg, y = hp, color = gear)) +
  geom_point() + 
  scale_color_ipea(discrete = F)
Run Code Online (Sandbox Code Playgroud)

此代码返回以下错误:“错误:向离散刻度提供连续值”

ggplot(data = mtcars, aes(x = mpg, y = hp, color = as.character(gear))) +
  geom_point() + 
  scale_color_ipea(discrete = T)
Run Code Online (Sandbox Code Playgroud)

所以我需要手动设置,scale_color_ipea(discrete = T)但我希望该功能能够自动检测列的类别并相应地使用足够的色标。

ggplot(data = mtcars, aes(x = mpg, y = hp, color = as.character(gear))) +
  geom_point() + 
  scale_color_ipea(discrete = T)
Run Code Online (Sandbox Code Playgroud)

有人会建议如何做到这一点吗?

All*_*ron 7

scale_color_ipea我将通过创建 S3 类对象,然后定义一个方法,为扩展您的包留出空间ggplot_add

此机制允许您询问绘图对象,以根据数据类型完全自动选择离散或连续比例。

scale_color_ipea <- function(discrete = FALSE, ...) {
  structure(list(...), class = "scale_chooser")
}

ggplot_add.scale_chooser <- function(object, plot, name) {
  args <- object
  var <- rlang::eval_tidy(rlang::quo_squash(plot$mapping$colour), plot$data)
  discrete <- !is.numeric(var)
  if(discrete) {
    return(plot + 
             do.call("discrete_scale",
                     c(list(aesthetics = "color", scale_name = "ipea", 
                     palette = colorRampPalette(c("red", "green", "blue"))),
                     args)))
  }
  return(plot + 
           do.call("continuous_scale", 
                   c(list(aesthetics = "color", scale_name = "ipea", 
                   palette = function(x) {
                     colorRamp(c("red", "green", "blue"))(x) |>
                       apply(1, \(x) do.call("rgb", as.list(x/255)))
                   }), args, guide = "colourbar")))
}
Run Code Online (Sandbox Code Playgroud)

现在允许:

ggplot(data = mtcars, aes(x = mpg, y = hp, color = gear)) +
  geom_point() +
  scale_color_ipea()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

ggplot(data = mtcars, aes(x = mpg, y = hp, color = factor(gear))) +
  geom_point() +
  scale_color_ipea()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

这里有一些注意事项。完整的实现可能需要向后迭代绘图对象中的所有图层,以防颜色仅在基本 ggplot 调用之后定义(这种情况经常发生)。每个层都需要对其mapping进行data评估,以确定颜色是否是专门映射到那里的而不是继承的。在现实世界的实现中,您当然也会将离散和连续调色板函数分开,以保持代码整洁和灵活。

  • @rafa.pereira 在 `ggplot_add` 中我们可以访问 ggplot 对象本身。它有一个名为“layers”的成员,其中包含几何对象,每个对象都有一个“mapping”对象,其中包含放入“aes”中的信息。因此,我们可以执行 `for(i in seq_along(plot$layers)) {` 并提取每个 `plot$layers[[i]]` 的数据/美学信息,就像我在上面的代码中对整个图所做的那样。完整的实现将非常耗时,但我认为我已经将其阐明得足够好,足以让那些有足够技能的人编写自己的包来自己实现它。 (2认同)