ggplot2:在灵活的绘图函数中使用颜色/形状/...在 aes() 的内部和外部

ggplot2: use colour / shape / ... inside and outside of aes() in a flexible plotting function

目标

我想要一个函数来处理一些输入 X 并使用 geom_point.

生成一个 gglot 图表

该函数应该允许将 X 的列映射到 aes() 中的各种美学(通过参数 .shapefac.colfac 等),但也允许设置例如在 aes().

之外手动点颜色和形状(例如 colour = "tomato"

问题

如果提供 .shapefac.colfac 参数,美学将分别被 shapecolour 的规范覆盖。这被解释为例如here.

我试过的

一种解决方法是删除 shapecolour 参数,并允许使用 geom_point 中的 ... 指定它们。这可行,但需要一些高级 R 知识才能使用此类功能。

问题

有人知道有没有

非常感谢任何提示或解释!

以下函数和图表有望说明问题。

定义函数

library(mlbench)
data("Ionosphere")

cplot <- function(X, v = 1:ncol(X), .shapefac = NULL, .colfac = NULL, shape = 21, colour = "black",
                  center = TRUE, scale = FALSE, x = 1, y = 2, plot = TRUE) {
  
  library(ggplot2)
  # some code processing X to Y
  d.pca <- prcomp(X, center = center, scale. = scale)
  Y <- data.frame(X, d.pca$x)
  v <- round(100 * (d.pca$sdev^2 / sum(d.pca$sdev^2)), 2)
  
  # plot PCA
  p <- ggplot(Y, aes_string(x = paste0("PC",x), y = paste0("PC",y))) +
    geom_point(aes_string(shape = .shapefac, colour = .colfac),
               shape = shape, color = colour) +
    labs(x = paste0("PC ", x, " (", v[x], "%)"),
         y = paste0("PC ", x, " (", v[y], "%)")) +
    theme_bw()
  if (plot) print(p)
  invisible(p)
}

在 aes() 之外设置颜色和形状参数

这可以正常工作。

cplot(Ionosphere, v = 3:34, colour = "tomato", shape = 4)

设置内部形状 aes() 当外部形状 aes() 的默认值为 21

aes() 之外的默认 shape = 21 覆盖形状美学。

cplot(Ionosphere, v = 3:34, .shapefac = "Class")

设置内部颜色 aes() 当外部颜色 aes() 默认为“黑色”

aes() 之外的默认 colour = "black" 覆盖颜色美学。

cplot(Ionosphere, v = 3:34, .colfac = "Class")

尝试将默认形状和颜色设置为 NULLNA

失败
# results in an empty plot (shape = NA)
cplot(Ionosphere, v = 3:34, .shapefac = "Class", shape = NA)
#> Warning: Removed 351 rows containing missing values (geom_point).

# results in an error
cplot(Ionosphere, v = 3:34, .shapefac = "Class", shape = NULL)
#> Error: Aesthetics must be either length 1 or the same as the data (351): shape

reprex package (v2.0.1)

于 2021-09-20 创建

实现您想要的结果的一个选项可能如下所示:

  1. 如果提供美学设置颜色 and/or 形状参数为 NULL
  2. 利用 modifyList 构建要传递给 geom_point 的参数列表,其中包括映射和非 NULL 参数。使用 modifyList 会掉落任何 NULL.
  3. 利用 do.call 调用带有参数列表的 geom_point

注意:我将您的函数稍微更改为 select 仅用于 PCA 的数字列。

library(mlbench)
library(ggplot2)

data(Ionosphere)

cplot <- function(X, .shapefac = NULL, .colfac = NULL, shape = 21, colour = "black",
                  center = TRUE, scale = FALSE, x = 1, y = 2, plot = TRUE) {
  
  col_numeric <- unlist(lapply(X, is.numeric))
  
  # some code processing X to Y
  d.pca <- prcomp(X[, col_numeric], center = center, scale. = scale)
  Y <- data.frame(X, d.pca$x)
  v <- round(100 * (d.pca$sdev^2 / sum(d.pca$sdev^2)), 2)
  
  colour <- if (is.null(.colfac)) colour
  shape <- if (is.null(.shapefac)) shape
  
  mapping <- aes_string(shape = .shapefac, colour = .colfac)
  args <- modifyList(list(mapping = mapping), list(color = colour, shape = shape))
  
  geom <- do.call("geom_point", args)
  
  p <- ggplot(Y, aes_string(x = paste0("PC", x), y = paste0("PC", y))) +
    geom +
    labs(
      x = paste0("PC ", x, " (", v[x], "%)"),
      y = paste0("PC ", x, " (", v[y], "%)")
    ) +
    theme_bw()
  if (plot) print(p)
  invisible(p)
}

cplot(Ionosphere, colour = "tomato", shape = 4)

cplot(Ionosphere, .shapefac = "Class")

cplot(Ionosphere, .colfac = "Class")

cplot(Ionosphere, .colfac = "Class", .shapefac = "Class")

cplot(Ionosphere, .shapefac = "Class", shape = NULL)