New method for plot - how to export? - r

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?

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.

A few problems:
Don't include a generic that is already defined elsewhere. Just add your method.
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!).

Related

Can't fix warning when redefining log as a generic

I would like to make the log function a generic so that I can alter it's behavior under some newclass.
I have a minimal package with a DESCRIPTION file:
Package: logmethod
Type: Package
Title: A new Log Method
Version: 0.1
Date: 2017-03-23
Author: Me
Maintainer: Who to complain to <yourfault#somewhere.net>
Description: More about what it does (maybe more than one line)
License: MIT
LazyData: TRUE
RoxygenNote: 5.0.1
And the R Code, based on what I've learned at Writing R Extensions and Is it bad style to redefine non-S3 base functions as S3 functions in an R package?
#' #name log_method
#' #title A New Log Method
#'
#' #description A new \code{log} method
#'
#' #param x a numeric, complex, or measured variable
#' #param base a positive or complex measured variable: the base with respect to which
#' logarithms are computed. Defaults to \emph{e}=\code{exp(1)}.
#' #param ... Additional arguments to pass to other methods.
#'
#' #export
log <- function(x, base, ...)
{
UseMethod("log")
}
#' #rdname log_method
#' #export
log.default <- function(x, base, ...)
{
base::log(x, base)
}
#' #rdname log_method
#' #export
log.newclass <- function(x, base, ...)
{
print("See, it dispatched")
log.default(as.numeric(x), as.numeric(base), ...)
}
When I run check, I keep getting the warning
checking S3 generic/method consistency ... WARNING
Warning: declared S3 method 'log.default' not found
Warning: declared S3 method 'log.newclass' not found
See section 'Generic functions and methods' in the 'Writing R
Extensions' manual.
When I install the package, I'm able to use log.default and log.newclass, so I'm not sure how to interpret this warning that the methods are not found. Turning an R S3 ordinary function into a generic describes how to make an S4 function, but I'd like to stick to S3 if possible. I would love to know why I keep getting this warning.
EDIT:
The NAMESPACE might also be useful.
# Generated by roxygen2: do not edit by hand
S3method(log,default)
S3method(log,newclass)
export(log)
It turns out the piece of the puzzle I was missing is that log and most of its cousins are already generic. From the ?log documentation details
All except logb are generic functions: methods can be defined for them
individually or via the Math group generic.
Thus, the proper coding for the new methods would have been the following (notice the lack of a UseMethod call)
log.default <- function(x, base, ...)
{
base::log(x, base)
}
log.newclass <- function(x, base, ...)
{
print("See, it dispatched")
log.default(as.numeric(x), as.numeric(base), ...)
}
On the other hand, since logb is not defined as a generic, that is a case where the instructions in Writing R Extensions would have been relevant (because dispatch is not yet designed)
logb <- function(x, base, ...)
{
UseMethod("logb")
}
logb.default <- function(x, base, ...)
{
base::logb(x, base)
}
logb.newclass <- function(x, base, ...)
{
print("See, it dispatched")
logb.default(as.numeric(x), as.numeric(base), ...)
}
So if you're coming across an warning like in the question, it may be worth checking into whether or not the base version of the function isn't already a generic.

Include ggplot2 function in package

I am trying to include the following ggplot2 helper function in a package [it wraps labels in grid_facet(.~variable, labeller = "plot.label.wrap")]:
#' Label wrapper for ggplot
#'
#' Include in the facet_grid option of ggplot.
#' #param variable
#' #param value
#' #return wrapper
#' #export
plot.label.wrap <- function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
My DESCRIPTION file includes: Imports: ggplot2. The scripts that uses the function includes: library(ggplot2).
The package builds, reloads and gives the documentation upon ?plot.label.wrap. It can be found:
> getAnywhere(plot.label.wrap)
A single object matching ‘plot.label.wrap’ was found
It was found in the following places
registered S3 method for plot from namespace mypackage
namespace:mypackage
with value
function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
<environment: namespace:mypackage>
However:
> plot.label.wrap
Error: object 'plot.label.wrap' not found
So my question is, why is this function found in the namespace of mypackage but not on the command line itself?
the solution in the comments was to be more specific about the export like below
#' Label wrapper for ggplot
#'
#' Include in the facet_grid option of ggplot.
#' #param variable
#' #param value
#' #return wrapper
#' #export plot.label.wrap
plot.label.wrap <- function(variable, value) {
lapply(strwrap(as.character(value), width=15, simplify=FALSE),
paste, collapse="\n")
}
roxygen tries to be smart about things like the #usage, #details, and #exports to make things simplier, but sometimes, like in this example, it doesn't always work out.
plot is an S3 generic method which can be defined as plot.someclass which will create a plotting method for some object x with class "someclass" and can be called simply by plot(x).
roxygen thinks that someclass for your package was "label.wrap" and exported plot.label.wrap as an S3 method rather than a normal function, expecting you to use it as plot(x) where class(x) is "label.wrap" and not trying to use plot.label.wrap directly as you tried (and found it doesn't work).
Alternatively, like #shadow mentioned, you could avoid this confusion by not using periods in function names, eg plot_label_wrap, plot_label.wrap,plot_labelwrap, etc. You don't have to, but in a few rare circumstances, using periods causes unexpected behaviors.

Roxygen documentation [duplicate]

I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.

R-oxygen documentation of S3 method produces error while check [duplicate]

I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.

How to properly document a S3 method of a generic from a different package, using Roxygen?

I am writing a package that defines a new class, surveyor, and a print method for this, i.e. print.surveyor. My code works fine and I use roxygen for inline documentation. But R CMD check issues a warning:
Functions/methods with usage in
documentation object 'print.surveyor'
but not in code: print
I have used the following two pages, written by Hadley, as inspiration:
Namespaces and Documenting functions, both of which states that the correct syntax is #method function-name class
So my question is: What is the correct way of documenting the print method for my new class using Roxygen? And more specifically, how do I get rid of the warning?
Here is my code: (The commented documentation indicated attempts at fixing this, none of which worked.)
#' Prints surveyor object.
#'
#' Prints surveyor object
#'
## #' #usage print(x, ...)
## #' #aliases print print.surveyor
#' #param x surveyor object
#' #param ... ignored
#' #S3method print surveyor
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
And the roxygenized output, i.e. print.surveyor.Rd:
\name{print.surveyor}
\title{Prints surveyor object.}
\usage{print(x, ...)
#'}
\description{Prints surveyor object.}
\details{Prints surveyor object
#'}
\alias{print}
\alias{print.surveyor}
\arguments{\item{x}{surveyor object}
\item{...}{ignored}}
Update
As of roxygen2 > 3.0.0 the package has gotten a lot smarter at figuring all this out for you. You now just need the #export tag and roxygen will work out what kind of thing you are documenting and do the appropriate thing when writing the NAMESPACE etc during conversion.
There are exceptions where you may need to help out roxygen. An example that Hadley Wickham uses in his R Packages book is all.equal.data.frame. There is ambiguity in that function name as to what is the class and what is the generic function (all, all.equal, or all.equal.data)?
In such cases, you can help roxygen out by explicitly informing it of the generic and class/method, e.g.
#method all.equal data.frame
The original answer below explains more about the older behaviour if you need to explicitly use #method.
Original
The function should be documented with the #method tag:
#' #method print surveyor
On initial reading, #hadley's document was a little confusing for me as I am not familiar with roxygen, but after several readings of the section, I think I understand the reason why you need #method.
You are writing full documentation for the print method. #S3method is related to the NAMESPACE and arranges for the method to be exported. #S3method is not meant for documenting a method.
Your Rd file should have the following in the usage section:
\method{print}{surveyor}(x, ...)
if this works correctly, as that is the correct way to document S3 methods in Rd files.
As of roxygen2 > 3.0.0., you only need #export because roxygen can figure out that print.surveyor is an S3 method. This means that you now only need
#' Prints surveyor object.
#'
#' #param x surveyor object
#' #param ... ignored
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
However, in this case since the documentation isn't very useful, it'd probably better to just do:
#' #export
print.surveyor <- function(x, ...){
cat("Surveyor\n\n")
print.listof(x)
}
#export only works if the generic is loaded. If the generic is in another package you need to import the generic. With current roxygen this is solved with a block like
#' #importFrom tibble data_frame
#' #export
tibble::data_frame
taken from dplyr/R/reexport-tibble.r . In this example, the data_frame method is imported from the tibble package, and tibble::data_frame is exported. Such re-exported objects are then documented in a reexports.Rd file that - needless to say - satisfies R CMD check.

Resources