Electrino
Electrino

Reputation: 2900

How to make S3 generic plotting function in R?

So I have been trying to make an S3 generic plotting function in R... I have read several blogs and examples explaining S3 functions... but I'm still having trouble figuring this out. In my package I have a function that creates a matrix. Then, I also have another function that takes the created matrix as an argument and then plots this matrix as a heat-map. I am trying to turn this second function (i.e., plotting heat-map) into an S3 generic function. The example below will hopefully explain what I mean.

To begin I have a function to create a matrix:

#' myMatrix
#'
#' @description Creates Matrix
#'
#' @param rows No of rows
#' @param cols No of cols
#'
#' @importFrom stats "runif"
#'
#' @export

myMatrix <- function(rows = 10, cols = 10){

n <- rows   # no or rows
p <- cols    # no of cols

# Create matrix of values
myMat <- matrix(runif(n*p, 0, 1), nrow=n)               # Create matrix
colnames(myMat) <- paste0("x", 1:p)                     # Name columns
rownames(myMat) <- paste0("x", 1:p)                     # Name rows
return(myMat)
}

I would then store the result of the matrix like so:

mat <- myMatrix(10,10)

Then, in a separate script, I was trying to create the S3 generic plotting function, like so:

#' heatMapTEST
#'
#' @description Plots plot
#'
#' @param myMat Given Matrix
#'
#' @importFrom ggplot2 "ggplot"
#'
#' @export

heatMapTEST <- function(myMat){
  UseMethod('plot')}

#' @export
plot.heatMapTEST <- function(myMat){

  df <- reshape2::melt(myMat, c("x", "y"), value.name = "z")
  head(df)
  ggplot(data=df,aes(x=x,y=y,fill=z))+
    geom_tile()
}

And then (I guess) I would call it like so:

plot(heatMapTEST(mat))

But this throws back an error saying:

Error in h(simpleError(msg, call)) : error in evaluating the argument 'x' in selecting a method for function 'plot': no applicable method for 'plot' applied to an object of class "c('matrix', 'array', 'double', 'numeric')"

I'm very new to writing S3 methods, so really I have no idea if I'm even partially correct in how im doing this... any suggestions as to how I would create a generic S3 to allow me to use the heatMapTEST function with the generic plot function?

Upvotes: 0

Views: 811

Answers (1)

MrFlick
MrFlick

Reputation: 206606

The S3 methods work when you add classes to your objects. If you want your matrix to have a special plotting method, then you just need to add a class to it. Observe

myMatrix <- function(rows = 10, cols = 10){
  
  n <- rows   # no or rows
  p <- cols    # no of cols
  
  # Create matrix of values
  myMat <- matrix(runif(n*p, 0, 1), nrow=n)               # Create matrix
  colnames(myMat) <- paste0("x", 1:p)                     # Name columns
  rownames(myMat) <- paste0("x", 1:p)                     # Name rows
  class(myMat) <- c("heatMapTEST", class(myMat))
  return(myMat)
}
class(myMatrix(10, 10))
# [1] "heatMapTEST" "matrix"      "array"  

So this function now has the class "heatMapTEST" but it will also behave like a matrix is no special methods for that class exist. When you call plot(), it will look to match the first class it can. You can see all the existing generic plot methods with methods(plot). You can create your own just as you did above

plot.heatMapTEST <- function(myMat){
  df <- reshape2::melt(myMat, c("x", "y"), value.name = "z")
  head(df)
  ggplot(data=df,aes(x=x,y=y,fill=z))+
    geom_tile()
}

and you would just call plot() on the object returned from myMatrix to get your plot

plot(myMatrix(10,10))

enter image description here

Upvotes: 4

Related Questions