将 ggplot2 图层分配给字符串并根据需要进行评估

Mik*_*kko 2 r ggplot2

背景

我正在尝试加速R 包的函数,该函数使用 ggplot2 绘制高分辨率地图。该函数basemap使用较大的 shapefile(每个 15 Mb)绘制斯瓦尔巴群岛地图。该地图是使用两个不同的 shapefile 图层(土地和冰川)以及一组“定义”(例如主题、轴比例和网格线)创建的。按照现在编写的代码,绘制地图大约需要 30 秒。

我的想法是,如果我可以打破代码片段中的图层并允许用户不绘制冰川,那么该函数的执行速度将提高两倍。另外,如果我可以将 ggplot2 语法指定为文本字符串并仅评估所需的字符串,那么 R 就不会浪费时间创建函数未使用的 ggplot2 对象。

我知道如何使用if else语句来做到这一点,但我想避免多次编写定义。似乎可以分配scale_x_continuous()给一个对象,但是分配scale_x_continuous() + scale_y_continuous()会产生错误:

scale_x_Continous() + scale_y_Continous() 中的错误:二元运算符的非数字参数

问题

如何将 ggplot2 轴定义分配给文本字符串并将它们与数据层粘贴在一起?

例子

我以iris数据集为例,这样大家就不用下载PlotSvalbard目前又大又乱的包了。请注意,我知道如何将颜色映射到变量。这里的要点只是为了将 shapefile 说明为iris数据集的两个子集:

library(ggplot2)
data(iris)

## Datasets to imitate the shapefile layers
ds1 <- subset(iris, Species == "setosa")
ds2 <- subset(iris, Species == "versicolor")

## Example how the basemap function works at the moment:

ggplot() + geom_point(data = ds1, aes(x = Sepal.Length, y = Sepal.Width), color = "red") +
geom_point(data = ds2, aes(x = Sepal.Length, y = Sepal.Width), color = "blue") +
scale_x_continuous("Longitude", breaks = seq(3, 8, by = 0.5)) +
scale_y_continuous("Latitude", breaks = seq(1,5, by = 1)) + theme_bw()

## Now I would like to plot ds2 only if user defines "keep.glaciers = TRUE"

land <- ggplot() + geom_point(data = ds1, aes(x = Sepal.Length, 
y = Sepal.Width), color = "red")

glacier <- geom_point(data = ds2, aes(x = Sepal.Length, y = Sepal.Width),
 color = "blue")

def <- scale_x_continuous("Longitude", breaks = seq(3, 8, by = 0.5)) +
scale_y_continuous("Latitude", breaks = seq(1,5, by = 1)) + theme_bw() ## Error!
# Error in +scale_x_continuous("Longitude", breaks = seq(3, 8, by = 0.5)) :
#  invalid argument to unary operator

## The ultimate goal:
keep.glaciers = TRUE

if(keep.glaciers) {
  land + glacier + def # error, see above
} else {
  land + def
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*ter 5

您可以将图层保留在 a 中list并使用+运算符 with ggplot

例如,该函数将、和图层plot_glaciers保存在列表中。语句控制层的构造。该函数将返回具有所需层的对象。landdefglacierifglacierggplot

plot_glaciers <- function(keep_glaciers = TRUE) {
  layers <- vector('list')

  layers$land    <- geom_point(data = ds1, aes(x = Sepal.Length, y = Sepal.Width), color = "red")
  layers$def     <- list(scale_x_continuous("Longitude", breaks = seq(3, 8, by = 0.5)),
                    scale_y_continuous("Latitude", breaks = seq(1,5, by = 1)),
                    theme_bw())

  if (keep_glaciers) {
    layers$glacier <- geom_point(data = ds2, aes(x = Sepal.Length, y = Sepal.Width), color = "blue")
  } 

  ggplot() + layers
}

plot_glaciers(TRUE)
plot_glaciers(FALSE)
Run Code Online (Sandbox Code Playgroud)