rr-s4

Convert a tibble into an S4 Object


I'm trying to learn how to work with S4 objects. I have a csv file of data:

class(data)
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame"

str(data)
spec_tbl_df [120,877 x 5] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ id       : num [1:120877] 14 14 14 14 14 14 14 14 14 14 ...
 $ visit    : num [1:120877] 0 0 0 0 0 0 0 0 0 0 ...
 $ room     : chr [1:120877] "bedroom" "bedroom" "bedroom" "bedroom" ...
 $ value    : num [1:120877] 6 6 2.75 2.75 2.75 2.75 6 6 2.75 2.75 ...
 $ timepoint: num [1:120877] 53 54 55 56 57 58 59 60 61 62 ...

and I want to convert it into an S4 object that I am creating.

Make_LD <- setClass("LongitudinalData",
                    slots = c(id = "numeric"
                              visit = "numeric",
                              room = "character",
                              value = "numeric",
                              timepoint = "numeric"))

x <- Make_LD(data)

However I have been hitting an error

Error in .nextMethod(.Object = .Object, ... = ...) : 
  cannot use object of class “spec_tbl_df” in new():  class “LongitudinalData” does not extend that class

I don't know how to troubleshoot it. I've tried using setOldClass and contains = "spec_tbl_df", but it seems to coerce it to an S3 object instead of an S4.

Any help/guidance would be greatly appreciated


Solution

  • The problem is that there is no initialize method for your class, so it doesn't know what to do when given a data frame (or tibble). You either need to pass all the individual columns as arguments to each slot, or to create an initialize method that does it for you.

    For example, suppose we set up the class definition and initialuze method like this:

    Make_LD <- setClass("LongitudinalData",
                        slots = c(id = "numeric",
                                  visit = "numeric",
                                  room = "character",
                                  value = "numeric",
                                  timepoint = "numeric"))
    
    setMethod("initialize", "LongitudinalData",
              function(.Object, data) {
                .Object@id <- data$id
                .Object@visit <- data$visit
                .Object@room <- data$room
                .Object@value <- data$value
                .Object@timepoint <- data$timepoint
                .Object
              })
    

    And we have a toy data frame with the correct names and types:

    df <- data.frame(id = 1:3, visit = 4:6, room = c("A", "B", "C"),
                     value = 8:10, timepoint = 11:13)
    

    We can now simply do

    Make_LD(df)
    #> An object of class "LongitudinalData"
    #> Slot "id":
    #> [1] 1 2 3
    #> 
    #> Slot "visit":
    #> [1] 4 5 6
    #> 
    #> Slot "room":
    #> [1] "A" "B" "C"
    #> 
    #> Slot "value":
    #> [1]  8  9 10
    #> 
    #> Slot "timepoint":
    #> [1] 11 12 13
    

    Created on 2022-11-21 with reprex v2.0.2