# object programming setClass("BMI", representation(weight = "numeric", size = "numeric")) setMethod("show","BMI", function(object) { cat("BMI=",object@weight/(object@size^2)," \n ") } ) (myBMI = new("BMI", weight = 85, size = 1.84)) (herBMI = new("BMI", weight = 62, size = 1.6)) # Type matters (weight = "Hello") new("BMI", weight = "Hello", size = 1.84) # Validity checking SizeMe = 1.84 setValidity("BMI", function(object) { if(object@size<0){ return("negative size") } else { return(TRUE) } } ) new("BMI", weight = 85, size = -1.84) # Inheritance setClass("BMIplus", representation(sex = "character"), contains = "BMI") (new("BMIplus", size = 1.76, weight = 84, sex = "Male")) # An example setClass(Class = "Trajectories", representation = representation(times = "numeric", traj = "matrix")) new(Class = "Trajectories") new(Class = "Trajectories", times = c(1,3,4)) new(Class = "Trajectories", times = c(1,3), traj = matrix(1:4, ncol = 2)) trajPitie = new(Class = "Trajectories") trajCochin = new(Class = "Trajectories", times = c(1,3,4,5), traj = rbind( c(15, 15.1, 15.2, 15.2), c(16, 15.9, 16, 16.4), c(15.2, NA, 15.3, 15.3), c(15.7, 15.6, 15.8, 16) ) ) trajStAnne = new(Class = "Trajectories", times = c(1:10, (6:16)*2), traj = rbind( matrix(seq(16, 19, length = 21), ncol = 21, nrow = 50, byrow = TRUE), matrix(seq(15.8, 18, length = 21), ncol = 21, nrow = 30, byrow = TRUE) ) + rnorm(21*80, 0, 0.2) ) # Default values setClass(Class = "TrajectoriesBis", representation = representation(time = "numeric", traj = "matrix"), prototype = prototype(time = 1, traj = matrix(0))) (new(Class = "TrajectoriesBis")) # Remove an object removeClass("TrajectoriesBis") (new(Class = "TrajectoriesBis")) # The empty object myObject = matrix(nrow = 0, ncol = 0) length(myObject) == 0 # numeric()and numeric(0) are empty numeric # character() and character(0) are empty character # integer() and integer(0) are empty integer # factor() is empty factor. factor(0) indicates a factor of length 1 containing the element zero # matrix() is a matrix with one line and one column containing NA. In any case, it is not # an empty matrix. To define an empty matrix, it is necessary to use matrix(nrow = 0, ncol = 0) # array() is an array with one line and one column contain NA # To see an object slotNames("Trajectories") getSlots("Trajectories") getClass("Trajectories") # Methods size = rnorm(10, 1.7, 10) weight = rnorm(10, 70, 5) group = as.factor(rep(c("A", "B"), 5)) par(mfrow = c(1,2)) plot(size~weight) plot(size~group) # setMethod setMethod( f = "plot", signature = "Trajectories", definition = function(x, y, ...){ matplot(x@times, t(x@traj), xaxt = "n", type = "l", ylab = "", xlab = "", pch = 1) axis(1, at = x@times) } ) par(mfrow = c(1,2)) plot(trajCochin) plot(trajStAnne) # Find arguments of a Method args(plot) # print setMethod("print", "Trajectories", function(x, ...){ cat("*** Class Trajectories, method Print *** \n") cat("* Times ="); print (x@times) cat("* Traj = \n"); print(x@traj) cat("******* End Print (trajectories) ******* \n") } ) print(trajCochin) print(trajStAnne) # show setMethod("show", "Trajectories", function(object){ cat("*** Class Trajectories, method Show *** \n") cat("* Times = "); print(object@times) nrowShow = min(10, nrow(object@traj)) ncolShow = min(10, ncol(object@traj)) cat("* Traj (limited to a matrix 10x10) = \n") print(formatC(object@traj[1:nrowShow, 1:ncolShow]), quote = FALSE) cat("******* End Show (trajectories) ******* \n") } ) trajStAnne # show can not take empty argument new("Trajectories") setMethod("show", "Trajectories", function(object){ cat("*** Class Trajectories, method Show *** \n") cat("* Times = "); print(object@times) nrowShow = min(10, nrow(object@traj)) ncolShow = min(10, ncol(object@traj)) cat("* Traj (limited to a matrix 10x10) = \n") if (length(object@traj)!=0){ print(formatC(object@traj[1:nrowShow, 1:ncolShow]), quote = FALSE) } else {} cat("******* End Show (trajectories) ******* \n") } ) new("Trajectories") # setGeneric setGeneric( name = "countMissing", def = function(object){ standardGeneric("countMissing") } ) setMethod( f = "countMissing", signature = "Trajectories", definition = function(object){ return(sum(is.na(object@traj))) } ) countMissing(trajCochin) # To avoid replacing a old generic function setGenericVerif = function(x, y){ if (!isGeneric(x)){ setGeneric(x, y) } else{} } # To see the methods showMethods(class = "Trajectories") getMethod(f = "plot", signature = "Trajectories") existsMethod(f = "plot", signature = "Trajectories") # Check validity setClass( Class = "Trajectories", representation(times = "numeric", traj = "matrix"), validity = function(object){ cat("*** Trajectories: inspector *** \n") if(length(object@times) != ncol(object@traj)){ stop("[Trajectories: validation] the number of temporal measurements does not correspond to the number of column of the matrix.") } else{} return(TRUE) } ) new(Class = "Trajectories", times = 1:2, traj = matrix(1:2, ncol = 2)) new(Class = "Trajectories", times = 1:3, traj = matrix(1:2, ncol = 2)) # Initializator setMethod( f = "initialize", signature = "Trajectories", definition = function(.Object, times, traj){ cat("*** Trajectories: initializator *** \n") rownames(traj) = paste("I", 1:nrow(traj), sep = "") .Object@times = times .Object@traj = traj return(.Object) } ) new(Class = "Trajectories", times = c(1, 2, 4, 8), traj = matrix(1:8, nrow = 2)) new(Class = "Trajectories", times = c(1, 2, 48), traj = matrix(1:8, nrow = 2)) # Initializator and validity combo setMethod( f = "initialize", signature = "Trajectories", definition = function(.Object, times, traj){ cat("*** Trajectories: initializator *** \n") if(!missing(traj)){ colnames(traj) = paste("T", times, sep = "") rownames(traj) = paste("I", 1:nrow(traj), sep = "") .Object@times = times .Object@traj = traj validObject(.Object) } return(.Object) } ) new(Class = "Trajectories", times = c(1, 2, 4, 8), traj = matrix(1:8, nrow = 2)) new(Class = "Trajectories", times = c(1, 2, 48), traj = matrix(1:8, nrow = 2)) # Constructor setClass( Class = "TrajectoriesBis", representation(times = "numeric", traj = "matrix") ) setMethod( f = "initialize", signature = "TrajectoriesBis", definition = function(.Object, nbWeek, BMIinit){ traj = outer(BMIinit, 1:nbWeek, function(init, week){ return(init + 0.1 * week)}) colnames(traj) = paste("T", 1:nbWeek, sep = "") rownames(traj) = paste("I", 1:nrow(traj), sep = "") .Object@times = 1:nbWeek .Object@traj = traj return(.Object) } ) new(Class = "TrajectoriesBis", nbWeek = 4, BMIinit = c(16, 17, 15.6)) # Constructor for user tr = trajectories = function(times, traj){ cat("*** Trajectories: constructor **** \n") new(Class = "Trajectories", times = times, traj = traj) } trajectories(times = c(1, 2, 4), traj = matrix(1:6, ncol = 3)) # Missing argument trajectories = function(times, traj){ if(missing(times)){ times = 1:ncol(traj) } new(Class = "Trajectories", times = times, traj = traj) } trajectories(traj = matrix(1:8, ncol = 4)) # Like traditional programming regularTrajectories = function(nbWeek, BMIinit){ traj = outer(BMIinit, 1:nbWeek, function(init, week){ return(init + 0.1 * week)}) times = 1:nbWeek return(new(Class = "Trajectories", times = times, traj = traj)) } regularTrajectories(nbWeek = 3, BMIinit = c(14, 15, 16)) # Accessor setGeneric("getTimes", function(object){ standardGeneric("getTimes") } ) setMethod("getTimes", "Trajectories", function(object){ return(object@times) } ) getTimes(trajCochin) setGeneric("getTraj", function(object){ standardGeneric("getTraj") } ) setMethod("getTraj", "Trajectories", function(object){ return(object@traj) } ) getTraj(trajCochin) # More complicated accessor setGeneric("getTrajInclusion", function(object){ standardGeneric("getTrajInclusion")}) setMethod("getTrajInclusion", "Trajectories", function(object){ return(object@traj[,1]) } ) getTrajInclusion(trajCochin) # set # The operator [ setMethod( f = "[", signature = "Trajectories", definition = function(x, i, j, drop){ if(i == "times"){ return(x@times) } else{} if(i == "traj"){ return(x@traj) } else{} } ) trajCochin["times"] trajCochin["traj"] # The operator [ and validity combo setReplaceMethod( f = "[", signature = "Trajectories", definition = function(x, i, j, value){ if(i == "times"){ x@times = value } else{} if(i == "traj"){ x@traj = value } else{} validObject(x) return(x) } ) trajCochin["times"] trajCochin["times"] = 2:5 # Interaction between classes setClass( Class = "Partition", representation = representation( nbGroups = "numeric", part = "factor" ) ) setGeneric("getNbGroups", function(object){ standardGeneric("getNbGroups")}) setMethod("getNbGroups", "Partition", function(object){ return(object@nbGroups)}) setGeneric("getPart", function(object){ standardGeneric("getPart")}) setMethod("getPart", "Partition", function(object){ return(object@part)}) partCochin = new(Class = "Partition", nbGroups = 2, part = factor(c("A", "B", "A", "B"))) partStAnne = new(Class = "Partition", nbGroups = 2, part = factor(rep(c("A", "B"), c(50, 30)))) # Signature setGeneric("test", function(x, y, ...){ standardGeneric("test")}) ## Example 1 setMethod("test", "numeric", function(x, y, ...){ cat("x is numeric = ", x, "\n")}) test(3.17) test("E") ## Example 2 setMethod("test", "character", function(x, y, ...){ cat("x is character = ", x, "\n")}) test("E") test(-8.54) ## Example 3 setMethod( f = "test", signature = c(x = "numeric", y = "character"), definition = function(x, y, ...){ cat("more complicated: ") cat("x is numeric =", x, "And y is a character =", y, "\n") } ) test(3.2, "E") test(3.2) test("E") # matplot setMethod( f = "plot", signature = c(x = "Trajectories", y = "Partition"), definition = function(x, y, ...){ matplot(x@times, t(x@traj[y@part == "A",]), ylim = range(x@traj, na.rm = TRUE), xaxt = "n", type = "l", ylab = "", xlab = "", col = 2) for(i in 2:y@nbGroups){ matlines(x@times, t(x@traj[y@part == LETTERS[i],]), xaxt = "n", type = "l", col = i+1) } axis(1, at = x@times) } ) par(mfrow = c(2, 2)) plot(trajCochin) plot(trajStAnne) plot(trajCochin, partCochin) plot(trajStAnne, partStAnne) # Any It is possible to take any argument showMethods(test) # Missing slot setMethod( f = "test", signature = c(x = "numeric", y = "missing"), definition = function(x, y, ...){ cat("x is numeric =", x, "and y is 'missing' \n")} ) test(3.17) test(3.17, "E") test(3.17, 2) # Inherience setClass( Class = "TrajPartitioned", representation = representation(listPartitions = "list"), contains = "Trajectories" ) tdPitie = new("TrajPartitioned") # unclass unclass(tdPitie) # Check if the initialize is specified partCochin2 = new("Partition", nbGroups = 3, part = factor(c("A", "C", "C", "B"))) tdCochin = new( Class = "TrajPartioned", times = c(1, 3, 4, 5), traj = trajCochin@traj, listPartitions = list(partCochin, partCochin2) ) getMethod("initialize", "TrajPartitioned") existsMethod("initialize", "TrajPartitioned") hasMethod("initialize", "TrajPartioned") selectMethod("initialize", "TrajPartitioned") # Set the initialize setMethod("initialize", "TrajPartitioned", function(.Object, times, traj, listPartitions){ cat("*** TrajPartitioned: initializator *** \n") if(!missing(traj)){ .Object@times = times .Object@traj = traj .Object@listPartitions = listPartitions } return(.Object) } ) tdCochin = new( Class = "TrajPartitioned", traj = trajCochin@traj, times = c(1, 3, 4, 5), listPartitions = list(partCochin, partCochin2) ) # Nextmethod setMethod( f = "print", signature = "TrajPartitioned", definition = function(x, ...){ callNextMethod() cat("the object also contains", length(x@listPartitions), "partition") cat("\n *** Fine of print (TrajPartitioned) *** \n") return(invisible()) } ) # as print(as(tdPitie, "Trajectories")) setMethod( f = "show", signature = "TrajPartitioned", definition = function(object){ show(as(object, "Trajectories")) lapply(object@listPartitions, show) } ) is(trajCochin, "TrajPartitioned") is(tdCochin, "Trajectories") # create an empty object tdStAnne = new("TrajPartitioned") as(tdStAnne, "Trajectories") = trajStAnne tdStAnne # Method to modify a field meanWithoutNa = function(x){ mean(x, na.rm = TRUE)} setGeneric("impute", function(.Object){ standardGeneric("impute")}) setMethod( f = "impute", signature = "Trajectories", definition = function(.Object){ average = apply(.Object@traj, 2, meanWithoutNa) for(iCol in 1:ncol(.Object@traj)){ .Object@traj[is.na(.Object@traj[,iCol]), iCol] = average[iCol] } return(.Object) } ) impute(trajCochin) trajCochin # Assign setMethod( f = "impute", signature = "Trajectories", definition = function(.Object){ nameObject = deparse(substitute(.Object)) average = apply(.Object@traj, 2, meanWithoutNa) for(iCol in 1:ncol(.Object@traj)){ .Object@traj[is.na(.Object@traj[,iCol]), iCol] = average[iCol] } assign(nameObject, .Object, envir = parent.frame()) return(.Object) } ) impute(trajCochin) trajCochin