rr-s3

S3 template which can take different formulas and numeric vectors as arguments


Please help me to make my code work. Here I'm trying to create an S3 template which can take different formulas and numeric vectors as arguments. Also I want to add a plot method, drawing the resulting figure. For now it throws an error:

Error in do.call(f, list(x, y)) : 'what' must be a function or character string

How to correctly use do.call here?

# template
chart <- function(x, y, f, ...) {
list(x, y,
do.call(f, list(x, y)),
class = "myChart")
}

# plot method
plot.myChart <- function(obj, ...) {
persp(x, y, z = outer(x, y, f))
}

# new object
c <- chart(seq(-6, 6, length = 100),
seq(-6, 6, length = 100),
f=sqrt(x^2+y^2))
c
plot.myChart(c)

Solution

  • There are a couple of tweaks you could make.

    1. Using do.call(f, list(x, y)) is the same as doing f(x, y), so you could just use that, but...
    2. ...you probably don't want to call the function at all during object creation, since that will just create an unnamed data member that you don't seem to use.
    3. You need to keep a copy of the function f for the print method. You can just store the function as a function.
    4. It would be best to name the elements of your object, and wrap it in structure to apply the class attribute properly.
    5. To access the objects inside the print method, you need to refer to them using the $ or [[ operators
    6. You only need to call plot, not plot.chart
    7. f needs to be a function during object creation. You are passing a function call.
    chart <- function(x, y, f, ...) {
      structure(list(x = x, y = y, f = f), class = "myChart")
    }
    
    # plot method
    plot.myChart <- function(obj, ...) {
      persp(obj$x, obj$y, z = outer(obj$x, obj$y, obj$f), ...)
    }
    
    # new object
    ch <- chart(x = seq(-6, 6, length = 100),
                y = seq(-6, 6, length = 100),
                f = function(x, y) sqrt(x^2 + y^2))
    
    plot(ch)
    

    enter image description here

    Created on 2022-05-10 by the reprex package (v2.0.1)