如何在另一个包中使用 ggplot_add
How to use ggplot_add inside another package
我正在尝试构建一个严重依赖 ggplot2 的数据可视化包,但有一些自定义快捷方式可以解决我遇到的一些日常问题。
我可以使用 ggplot_add
函数为来自脚本的自定义 class 扩展 +
的功能,但是当我将这些脚本添加到包中时,ggplot_add
不再有效。
下面我粘贴了一个 minrep,复制第一个需要创建一个包(我正在使用 RStudio),我称之为 SOExa。
该项目包含以下文件:
.Rbuildignore
^.*\.Rproj$
^\.Rproj\.user$
描述
Package: SOExa
Type: Package
Title: An minrep for a problem I'm having
Version: 0.1.0
Author: Col Bates
Maintainer: The package maintainer <yourself@somewhere.net>
Description: I want to use ggplot2's ggplot_add from inside another package, i.e. this one.
It seems that when I do I get an error.
License: GPLv2
Encoding: UTF-8
Imports:
dplyr,
magrittr,
tidyr,
glue,
ggplot2
LazyData: true
RoxygenNote: 7.1.1
我的项目文件SOExa.Rproj
一个名为 R 的文件夹,包含 minrep 使用示例:
R/designed_by.R
#' the function to add a 'designed by' to the plot
#' as a designed_by class
#'@export
designed_by<-function(x){
return(new_designed_by(x))
}
#' generic constructor.
#' @export
new_designed_by<-function(x){
x <- list('designed_by' = x)
class(x) <- 'designed_by'
return(x)
}
#' generic print for designed_by
#' @export
print.designed_by <- function(x){
print(paste('Designed by:', format(x)))
}
#' defines the addition of an designed_by object for
#' @export
ggplot_add.designed_by <- function(object, plot, objectname){
plot$designed_by <- object$designed_by
plot
}
ggplot_add <- function(x){
UseMethod("ggplot_add")
}
我运行下面的代码来构建Namespace文件
devtools::document()
创建了一个新文件:
命名空间
# Generated by roxygen2: do not edit by hand
S3method(ggplot_add,designed_by)
S3method(print,designed_by)
export(designed_by)
export(new_designed_by)
在此之后我安装并加载库:
devtools::install()
library(SOExa)
然后创建一个空地块:
p <- ggplot2::ggplot()
以下会报错:
p <- p + designed_by('Col Bates')
我得到的错误是:
# Error: Can't add `designed_by("Col Bates")` to a ggplot object.
# Run `rlang::last_error()` to see where the error occurred.
所以按照这些步骤:
rlang::last_error()
哪个returns
# <error/rlang_error>
# Can't add `designed_by("Col Bates")` to a ggplot object.
# Backtrace:
# 1. ggplot2:::`+.gg`(p, designed_by("Col Bates"))
# 2. ggplot2:::add_ggplot(e1, e2, e2name)
# 4. ggplot2:::ggplot_add.default(object, p, objectname)
# Run `rlang::last_trace()` to see the full context.
运行
rlang::last_trace()
我明白了
<error/rlang_error>
Can't add `designed_by("Col Bates")` to a ggplot object.
Backtrace:
x
1. \-ggplot2:::`+.gg`(p, designed_by("Col Bates"))
2. \-ggplot2:::add_ggplot(e1, e2, e2name)
3. +-ggplot2::ggplot_add(object, p, objectname)
4. \-ggplot2:::ggplot_add.default(object, p, objectname)
据此我可以推断调用 UseMethod('ggplot_add')
的 ggplot2::ggplot_add() 已调用决定应用函数 ggplot_add.default
,并且没有识别我的 class designed_by
.
顺便说一句,使用 print()
函数在库中确实有效。
print(designed_by('Col Bates'))
但是,如果我要获取脚本源代码,而不是像下面这样使用包:
source('./R/designed_by.R')
p <- p + designed_by('Col Bates')
它确实按照我期望的方式工作。
深入研究,我可以看到 class designed_by
上通用 ggplot_add
的来源是我的包。
sloop::s3_methods_generic("ggplot_add")
## A tibble: 1 x 4
# generic class visible source
# <chr> <chr> <lgl> <chr>
# 1 ggplot_add designed_by TRUE SOExa
而对于 ggplot classes 它是 'registered S3method'
> sloop::s3_methods_generic("ggplot_add")
## A tibble: 14 x 4
# generic class visible source
# <chr> <chr> <lgl> <chr>
# 1 ggplot_add by FALSE registered S3method
# 2 ggplot_add Coord FALSE registered S3method
# 3 ggplot_add data.frame FALSE registered S3method
# 4 ggplot_add default FALSE registered S3method
# 5 ggplot_add Facet FALSE registered S3method
# ...
我查看了 ggplot2 source code, but couldn't really figure out how this works. I've also been reading https://adv-r.hadley.nz/s3.html,但没有看到任何关于使用适用于来自另一个库的 classes 的 S3methods 的信息。
最好弄清楚是否可以将调用打包到我的自定义包中,或者我是否总是需要依赖采购。
谢谢。
这是一个经常困扰我的常见问题。您需要确保您的包可以访问 ggplot2
的 ggplot_add
通用函数。您可以通过以下两种方式之一执行此操作。
您需要在包裹中的某处包含以下行:
#' @import ggplot2
这将使所有 ggplot2 函数可用,或者如果您只使用该函数,请执行以下操作:
#' @importFrom ggplot2 ggplot_add
这有点不直观,但是仅仅因为 DESCRIPTION
文件说它导入了一个包,并不意味着您的包的命名空间将能够看到该包的功能。您始终可以通过查看 NAMESPACE
文件来检查这一点。当您包含上述建议时,您应该会在 NAMESPACE
文件
的底部看到以下行之一
import(ggplot2)
importFrom(ggplot2,ggplot_add)
如果您将 ggplot2
添加到 Depends
而不是 DESCRIPTION
文件中的 Imports
,您的设置应该可以正常工作。例如,如果我使用以下文件创建一个新包:
.Rbuildignore
^.*\.Rproj$
^\.Rproj\.user$
描述
Package: SOExa
Type: Package
Title: An minrep for a problem I'm having
Version: 0.1.0
Author: Col Bates
Maintainer: The package maintainer <yourself@somewhere.net>
Description: I want to use ggplot2's ggplot_add from inside another package, i.e. this one.
It seems that when I do I get an error.
License: GPLv2
Encoding: UTF-8
Depends: ggplot2
Imports:
dplyr,
magrittr,
tidyr,
glue
LazyData: true
RoxygenNote: 7.1.1
designed_by.R
#' the function to add a 'designed by' to the plot
#' as a designed_by class
#'@export
designed_by<-function(x){
return(new_designed_by(x))
}
#' generic constructor.
#' @export
new_designed_by<-function(x){
x <- list('designed_by' = x)
class(x) <- 'designed_by'
return(x)
}
#' generic print for designed_by
#' @export
print.designed_by <- function(x){
print(paste('Designed by:', format(x)))
}
#' defines the addition of an designed_by object for
#' @export
ggplot_add.designed_by <- function(object, plot, objectname){
plot$designed_by <- object$designed_by
plot
}
然后 运行 devtools::document()
给我:
命名空间
# Generated by roxygen2: do not edit by hand
S3method(ggplot_add,designed_by)
S3method(print,designed_by)
export(designed_by)
export(new_designed_by)
所以在我执行 devtools::install()
之后,我得到以下输出:
library(SOExa)
#> Loading required package: ggplot2
p <- ggplot(data = NULL, aes(x = 1:10, y = 1:10)) + geom_point()
p <- p + designed_by('Col Bates')
p
p$designed_by
#> [1] "Col Bates"
我正在尝试构建一个严重依赖 ggplot2 的数据可视化包,但有一些自定义快捷方式可以解决我遇到的一些日常问题。
我可以使用 ggplot_add
函数为来自脚本的自定义 class 扩展 +
的功能,但是当我将这些脚本添加到包中时,ggplot_add
不再有效。
下面我粘贴了一个 minrep,复制第一个需要创建一个包(我正在使用 RStudio),我称之为 SOExa。 该项目包含以下文件:
.Rbuildignore
^.*\.Rproj$
^\.Rproj\.user$
描述
Package: SOExa
Type: Package
Title: An minrep for a problem I'm having
Version: 0.1.0
Author: Col Bates
Maintainer: The package maintainer <yourself@somewhere.net>
Description: I want to use ggplot2's ggplot_add from inside another package, i.e. this one.
It seems that when I do I get an error.
License: GPLv2
Encoding: UTF-8
Imports:
dplyr,
magrittr,
tidyr,
glue,
ggplot2
LazyData: true
RoxygenNote: 7.1.1
我的项目文件SOExa.Rproj
一个名为 R 的文件夹,包含 minrep 使用示例:
R/designed_by.R
#' the function to add a 'designed by' to the plot
#' as a designed_by class
#'@export
designed_by<-function(x){
return(new_designed_by(x))
}
#' generic constructor.
#' @export
new_designed_by<-function(x){
x <- list('designed_by' = x)
class(x) <- 'designed_by'
return(x)
}
#' generic print for designed_by
#' @export
print.designed_by <- function(x){
print(paste('Designed by:', format(x)))
}
#' defines the addition of an designed_by object for
#' @export
ggplot_add.designed_by <- function(object, plot, objectname){
plot$designed_by <- object$designed_by
plot
}
ggplot_add <- function(x){
UseMethod("ggplot_add")
}
我运行下面的代码来构建Namespace文件
devtools::document()
创建了一个新文件:
命名空间
# Generated by roxygen2: do not edit by hand
S3method(ggplot_add,designed_by)
S3method(print,designed_by)
export(designed_by)
export(new_designed_by)
在此之后我安装并加载库:
devtools::install()
library(SOExa)
然后创建一个空地块:
p <- ggplot2::ggplot()
以下会报错:
p <- p + designed_by('Col Bates')
我得到的错误是:
# Error: Can't add `designed_by("Col Bates")` to a ggplot object.
# Run `rlang::last_error()` to see where the error occurred.
所以按照这些步骤:
rlang::last_error()
哪个returns
# <error/rlang_error>
# Can't add `designed_by("Col Bates")` to a ggplot object.
# Backtrace:
# 1. ggplot2:::`+.gg`(p, designed_by("Col Bates"))
# 2. ggplot2:::add_ggplot(e1, e2, e2name)
# 4. ggplot2:::ggplot_add.default(object, p, objectname)
# Run `rlang::last_trace()` to see the full context.
运行
rlang::last_trace()
我明白了
<error/rlang_error>
Can't add `designed_by("Col Bates")` to a ggplot object.
Backtrace:
x
1. \-ggplot2:::`+.gg`(p, designed_by("Col Bates"))
2. \-ggplot2:::add_ggplot(e1, e2, e2name)
3. +-ggplot2::ggplot_add(object, p, objectname)
4. \-ggplot2:::ggplot_add.default(object, p, objectname)
据此我可以推断调用 UseMethod('ggplot_add')
的 ggplot2::ggplot_add() 已调用决定应用函数 ggplot_add.default
,并且没有识别我的 class designed_by
.
顺便说一句,使用 print()
函数在库中确实有效。
print(designed_by('Col Bates'))
但是,如果我要获取脚本源代码,而不是像下面这样使用包:
source('./R/designed_by.R')
p <- p + designed_by('Col Bates')
它确实按照我期望的方式工作。
深入研究,我可以看到 class designed_by
上通用 ggplot_add
的来源是我的包。
sloop::s3_methods_generic("ggplot_add")
## A tibble: 1 x 4
# generic class visible source
# <chr> <chr> <lgl> <chr>
# 1 ggplot_add designed_by TRUE SOExa
而对于 ggplot classes 它是 'registered S3method'
> sloop::s3_methods_generic("ggplot_add")
## A tibble: 14 x 4
# generic class visible source
# <chr> <chr> <lgl> <chr>
# 1 ggplot_add by FALSE registered S3method
# 2 ggplot_add Coord FALSE registered S3method
# 3 ggplot_add data.frame FALSE registered S3method
# 4 ggplot_add default FALSE registered S3method
# 5 ggplot_add Facet FALSE registered S3method
# ...
我查看了 ggplot2 source code, but couldn't really figure out how this works. I've also been reading https://adv-r.hadley.nz/s3.html,但没有看到任何关于使用适用于来自另一个库的 classes 的 S3methods 的信息。
最好弄清楚是否可以将调用打包到我的自定义包中,或者我是否总是需要依赖采购。
谢谢。
这是一个经常困扰我的常见问题。您需要确保您的包可以访问 ggplot2
的 ggplot_add
通用函数。您可以通过以下两种方式之一执行此操作。
您需要在包裹中的某处包含以下行:
#' @import ggplot2
这将使所有 ggplot2 函数可用,或者如果您只使用该函数,请执行以下操作:
#' @importFrom ggplot2 ggplot_add
这有点不直观,但是仅仅因为 DESCRIPTION
文件说它导入了一个包,并不意味着您的包的命名空间将能够看到该包的功能。您始终可以通过查看 NAMESPACE
文件来检查这一点。当您包含上述建议时,您应该会在 NAMESPACE
文件
import(ggplot2)
importFrom(ggplot2,ggplot_add)
如果您将 ggplot2
添加到 Depends
而不是 DESCRIPTION
文件中的 Imports
,您的设置应该可以正常工作。例如,如果我使用以下文件创建一个新包:
.Rbuildignore
^.*\.Rproj$
^\.Rproj\.user$
描述
Package: SOExa
Type: Package
Title: An minrep for a problem I'm having
Version: 0.1.0
Author: Col Bates
Maintainer: The package maintainer <yourself@somewhere.net>
Description: I want to use ggplot2's ggplot_add from inside another package, i.e. this one.
It seems that when I do I get an error.
License: GPLv2
Encoding: UTF-8
Depends: ggplot2
Imports:
dplyr,
magrittr,
tidyr,
glue
LazyData: true
RoxygenNote: 7.1.1
designed_by.R
#' the function to add a 'designed by' to the plot
#' as a designed_by class
#'@export
designed_by<-function(x){
return(new_designed_by(x))
}
#' generic constructor.
#' @export
new_designed_by<-function(x){
x <- list('designed_by' = x)
class(x) <- 'designed_by'
return(x)
}
#' generic print for designed_by
#' @export
print.designed_by <- function(x){
print(paste('Designed by:', format(x)))
}
#' defines the addition of an designed_by object for
#' @export
ggplot_add.designed_by <- function(object, plot, objectname){
plot$designed_by <- object$designed_by
plot
}
然后 运行 devtools::document()
给我:
命名空间
# Generated by roxygen2: do not edit by hand
S3method(ggplot_add,designed_by)
S3method(print,designed_by)
export(designed_by)
export(new_designed_by)
所以在我执行 devtools::install()
之后,我得到以下输出:
library(SOExa)
#> Loading required package: ggplot2
p <- ggplot(data = NULL, aes(x = 1:10, y = 1:10)) + geom_point()
p <- p + designed_by('Col Bates')
p
p$designed_by
#> [1] "Col Bates"