簡體   English   中英

如何在另一個 package 中使用 ggplot_add

[英]How to use ggplot_add inside another package

我正在嘗試為嚴重依賴 ggplot2 的數據可視化構建 package,但對於我面臨的一些日常問題有一些自定義快捷方式。

我可以使用ggplot_add function 從腳本擴展自定義類的+功能,但是當我將這些腳本添加到 package 時, ggplot_add不再有效。

下面我粘貼了一個 minrep,要復制第一個需要創建一個 package(我正在使用 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/design_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")
  }

我運行以下代碼來構建命名空間文件

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)

然后創建一個空的 plot:

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()

哪個返回

# <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)

From this I can deduce that ggplot2::ggplot_add(), which calls UseMethod('ggplot_add') has invoked decided to apply the function ggplot_add.default , and hasn't recognised my class designed_by .

順便說一句,使用print() function 確實可以從庫中使用。

print(designed_by('Col Bates'))

但是,如果我要獲取腳本,而不是使用 package,如下所示:

source('./R/designed_by.R')
p <- p + designed_by('Col Bates')

它確實按我期望的方式工作。

深入研究,我可以看到 class designed_by的_by 上的通用ggplot_add的來源是我的 package。

 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 類,它是“注冊的 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源代碼,但無法真正弄清楚它是如何工作的。 我也一直在閱讀https://adv-r.hadley.nz/s3.html但沒有看到任何關於使用適用於另一個庫中的類的 S3 方法的信息。

很高興弄清楚 package 是否可以調用我的自定義 package,或者我是否總是需要依賴采購。

謝謝。

這是一個讓我很頭疼的常見問題。 您需要確保您的 package 可以訪問ggplot2ggplot_add通用 function。 您可以通過以下兩種方式之一進行此操作。

您需要在 package 的某處包含以下行:

#' @import ggplot2

這將使所有 ggplot2 功能可用,或者如果您只使用該 function ,請執行以下操作:

#' @importFrom ggplot2 ggplot_add

這有點不直觀,但僅僅因為DESCRIPTION文件說它導入了 package,並不意味着您的包的命名空間將能夠看到該包的功能。 您始終可以通過查看NAMESPACE文件來檢查這一點。 當您包含上面的建議時,您應該在NAMESPACE文件的底部看到以下行之一

import(ggplot2)
importFrom(ggplot2,ggplot_add)

如果您將ggplot2添加到Depends而不是DESCRIPTION文件中的Imports ,您的設置應該可以工作。 例如,如果我使用以下文件創建一個新的 package:

.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

設計的_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()之后,我得到以下 output:

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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM