New method for plot - how to export?
Asked Answered
F

2

5

I am making a package where I want to define a new method for plot. I am using roxygen in-source documentation. This question seems very similar to: How to properly document a S3 method of a generic from a different package, using Roxygen? and Roxygen2 - how to properly document S3 methods but I still cannot get it to work.

The relevant parts that are causing me trouble are:

#' Generic plot method
#'
#' @param x \dots
#' @param ... \dots
#' @export
plot <- function(x, ...) UseMethod("plot")

#' Default plot method
#'
#' @param x \dots
#' @param ... \dots
#' @importFrom graphics plot
#' @method plot default
#' @S3method plot default
plot.default <- function(x, ...) graphics::plot(x, ...)

#' Plotting function for ABI object
#'
#' Description.
#' 
#' @param x ABI object as generated by newABI.
#' @param base Character. Bases to look at.
#' @param ... Other options passed to plot().
#' @return Nothing. Side-effect: plots graphs.
#' @method plot ABI
#' @S3method plot ABI
plot.ABI <- function(x, base, ...) {
#Overly simplified
plot(1, 1, main = base)
}

When I run this and investigate methods(plot), there is no method defined for ABI objects. Accessing the function by ABI:::plot (ABI is the name of the package) does work. Using :: does not.

During the package build check, there is a warning:

* checking S3 generic/method consistency ... WARNING
plot:
  function(x)
plot.ABI:
  function(x, base, ...)
See section ‘Generic functions and methods’ of the ‘Writing R
Extensions’ manual.

It seems that there is a disagreement in arguments. But I don't understand this, since the generic has arguments x and ... and so does my ABI method (in addition to base).

So there are two problems, which I hope stem from the same issue: The plot.ABI method is not exported and the package check throws a warning.

How do I solve this?

Feathery answered 29/10, 2012 at 11:39 Comment(0)
R
5

A few problems:

  1. Don't include a generic that is already defined elsewhere. Just add your method.

  2. The signatures of every method must at least include every element in the generic, in the same order. It's annoying sometimes, but it's incontrovertible.

Update

I had said, "Your @export needs to list the function name," but apparently this is not correct. See the comments. Note also that listing the method should export it. I seem to recall needing an explicit export in cases where you aren't including the generic in your package's namespace, but I could be wrong (so often am!).

Retrorse answered 29/10, 2012 at 11:45 Comment(5)
You shouldn't need to export the plot method, you just need to register it, that's what @S3method does. @method is just used to document the function.Provenience
OK, great! I've tried endless possibilities and this was just the closest solution I'd arrived at so far. I did think it was odd to be redefining a generic. I've now removed the two first definitions, and re-ordered the plot.ABI arguments: plot.ABI(x, ..., base) And it works! Thanks.Feathery
re: @export, you don't need to write the function name (according to Hadley's examples). It export the "current" function. I think. github.com/yihui/roxygen2Feathery
@bdh_dtu you don't need @export at all. You only need that if you want the user to be able to call plot.ABI() (with out ABI:::), which invariably, but not always, you don't.Provenience
@GavinSimpson , yes, I understood. I just wanted to clarify that "@export" is a valid tag - a function name is not always required.Feathery
P
6

The problem is that your method needs to have the same arguments as the generic. Let's assume you are using the generic supplied with R:

> args(plot)
function (x, y, ...) 
NULL

Now plot() is actually a special case as you can essentially ignore that there is an argument y there.

So your method needs to be as you have it:

plot.ABI <- function(x, base, ...)

The issue is that, contrary to your quoted script, you must have redefined the generic as

plot(x)

and as that is missing ..., R CMD check will rightly complain.

So, don't document or provide the generic if it already exists.

Provenience answered 29/10, 2012 at 11:57 Comment(2)
The plot(x) thing is a mystery to me. I quoted it correctly, and it does give the error I posted. I noticed that plot is strange - that "y" doesn't need to be defined. Is the order important, though? Can the "..." always be at the end, and class-specific arguments appended to the generic arguments? I.e. can it be (x, base, ...) or must it be (x, ..., base)? Trial-and-error will quickly answer this, but I'm interested in understand the general structure and rules!Feathery
It can be function(x, base, ...) or function(x, ..., base). Essentially the ... in the definition of plot() is used as a placeholder for base, ... in the first version and ..., base in the second version. Think of ..., in this context, as just meaning "any other arguments that might be supplied".Provenience
R
5

A few problems:

  1. Don't include a generic that is already defined elsewhere. Just add your method.

  2. The signatures of every method must at least include every element in the generic, in the same order. It's annoying sometimes, but it's incontrovertible.

Update

I had said, "Your @export needs to list the function name," but apparently this is not correct. See the comments. Note also that listing the method should export it. I seem to recall needing an explicit export in cases where you aren't including the generic in your package's namespace, but I could be wrong (so often am!).

Retrorse answered 29/10, 2012 at 11:45 Comment(5)
You shouldn't need to export the plot method, you just need to register it, that's what @S3method does. @method is just used to document the function.Provenience
OK, great! I've tried endless possibilities and this was just the closest solution I'd arrived at so far. I did think it was odd to be redefining a generic. I've now removed the two first definitions, and re-ordered the plot.ABI arguments: plot.ABI(x, ..., base) And it works! Thanks.Feathery
re: @export, you don't need to write the function name (according to Hadley's examples). It export the "current" function. I think. github.com/yihui/roxygen2Feathery
@bdh_dtu you don't need @export at all. You only need that if you want the user to be able to call plot.ABI() (with out ABI:::), which invariably, but not always, you don't.Provenience
@GavinSimpson , yes, I understood. I just wanted to clarify that "@export" is a valid tag - a function name is not always required.Feathery

© 2022 - 2024 — McMap. All rights reserved.