Questions regarding the use of S4 methods in R - r

We were trying to program object oriented programming in R, using S4 methods. During our programming process, we came across some problems. Apparently, the use of S4 methods is not very well documented on the internet yet, therefore we hope that we can get answers to some of our questions here.
First question:
We were trying to make a vector/array/list.. of empty S4 objects. Searching the internet brought us to the following question in this forum:
Create a vector of empty S4 objects
As (similarly) described in one of the answers to the question above, we used the following code to create a list of empty S4 objects:
setClass("Name", representation(pos_x = "numeric", pos_y = "numeric", found =
"logical"), prototype(found = FALSE))
newList <- lapply(rep("Name", 2), new)
This works perfectly fine. However, when we are trying to call one slot (one variable) of the S4 method, this won't work. When we for example want to call the slot "pos_x", the following code
newList[1]#pos_x
is not working. The error message we receive is "Trying to get slot pos_x from an object of a basic class ("list") with no slots.
So, it seems as if the slots were not assigned to the S4 method, although they are clearly defined in the list.
Does anyone know how we can call a slot from one of the S4-methods/objects of the list?
Second question:
We would like to test whether one of the elements of the list above equals "NULL", as we would like to create the objects later on.
To check this, we tried:
newList[1] == NULL
This is however only resulting in "logical(0)".
Does anyone know how to do this?
Suggestions, remarks and questions are very welcome.
Thanks a lot!

The problem is maybe due to the use of [ instead of [[.
The command newList[1] returns a list of length one, whereas the command newList[[1]] returns an element of the list. You should therefore try:
newList[[1]]#pos_x

Related

What does #lx[i] mean in R?

So i looked into a guy's code and i saw these lines of code:
for(i in 1:getOmega(bh_w_f) + 1){
bh_w_f_qx[i] = (bh_w_f#lx[i] - bh_w_f#lx[i + 1])/bh_w_f#lx[i]
What does #lx[i] mean or do? I tried look it up on the internet but i could not find anything. Any ideas? I want to mention that these lines of code above are the first occurance of #lx[i] or lx[i] or lx alone, so no declaration before. I ran the code and it works, no error given, the function works properly.
bh_w_f_qx and bh_w_f are vectors declared before
EDIT : As said in the comments and in the first answer, bh_w_f is actually a S4 object, a lifetable made with function probs2lifetable from https://www.rdocumentation.org/packages/lifecontingencies/versions/1.3.7/topics/probs2lifetable but i could not find what lx wants to be. As i said, it's the first time that lx shows up in the code, with no external files included.
EDIT 2: Found out that the answer is in the returning format from probs2lifetable() function, that returns a lifetable class object which has lxas representing the number of lives at the beginning of age (x).
More about it here: https://www.rdocumentation.org/packages/lifecontingencies/versions/1.3.7/topics/lifetable-class
Thanks
# is the symbol used to pull attributes from S4 class objects in R. This syntax can be unusual because most people use S3 as it's simpler than S4. In the case of the code you posted, my guess is that you can get away with thinking of # as the equivalent of a $ for lists and data frames etc.

Is attributes() a function in R?

Help files call attributes() a function. Its syntax looks like a function call. Even class(attributes) calls it a function.
But I see I can assign something to attributes(myobject), which seems unusual. For example, I cannot assign anything to log(myobject).
So what is the proper name for "functions" like attributes()? Are there any other examples of it? How do you tell them apart from regular functions? (Other than trying supposedfunction(x)<-0, that is.)
Finally, I guess attributes() implementation overrides the assignment operator, in order to become a destination for assignments. Am I right? Is there any usable guide on how to do it?
Very good observation Indeed. It's an example of replacement function, if you see closely and type apropos('attributes') in your R console, It will return
"attributes"
"attributes<-"
along with other outputs.
So, basically the place where you are able to assign on the left sign of assignment operator, you are not calling attributes, you are actually calling attributes<- , There are many functions in R like that for example: names(), colnames(), length() etc. In your example log doesn't have any replacement counterpart hence it doesn't work the way you anticipated.
Definiton(from advanced R book link given below):
Replacement functions act like they modify their arguments in place,
and have the special name xxx<-. They typically have two arguments (x
and value), although they can have more, and they must return the
modified object
If you want to see the list of these functions you can do :
apropos('<-$') and you can check out similar functions, which has similar kind of properties.
You can read about it here and here
I am hopeful that this solves your problem.

R: modify any function applied to a S4 class

I've been developing a S4 class which is essentially a data.frame with a little bit of extra information. For the purposes of this question, the "extra" features of this class are irrelevant. What matters is that the class contains a data.frame object stored in one of it's slots. (I put the data.frame in a slot, instead of naming it a superclass, because I find that S4 classes which contain data.frames simplify the data.frames to lists for some reason).
Here's a basic example:
setClass('tmp_class', slots = c(df = 'data.frame'))
test_object <- new('tmp_class', df = data.frame(Num = 1:10, Let = letters[1:10]))
Now what I'd like to do is make it so that essentially any function applied to an object of this class is applied to the data.frame in slot #df. It's easy to write methods for specific functions to do this, like:
setMethod('dim', signature = c(x = 'tmp_class'), function(x) dim(x#df))
But I'm limited to only the functions I can think of, and any function invented by a user wouldn't work.
It is a simple matter to write a sort of wrapper/closure to modify a function to work on my class, like this:
tmp_classize <- function(func){
function(tmp, ...){ func(tmp#df, ...) }
}
So, rather than writing methods for, say, colnames() or ncol(), I could just run:
tmp_classize(colnames)(test_object)
or
tmp_classize(ncol)(test_object)
But what I'd like to do is somehow evoke my "tmp_classize" function on any function applied to my class, automatically. I can't figure out how to do it. I was thinking that if could somehow call a "universal method" with an input signature of class "tmp_class", and then use sys.function() to grab the actual function being called, maybe I could make something work, but A) there are recursion problems B) I don't know how to call such a "universal" method. It seems to me that the solution, if it exists at all, might necessitate non-standard evaluation, which I'd rather avoid, but might use if necessary.
Thanks!
P.S. I realize this undertaking may be unwise/poor programming technique, and I may never actually implement it in a package. Still I'm curious to know if it is possible.
P.P.S. I'd also be interested in the same idea applied to S3 classes!
In principal what you could do is make a classUnion for your class and data.frame and write methods for your class that deal with all of the ways to read and write to data.frames such as $, [, dim(), <- and many more. Then when other functions seek to use your new class as data.frame there will be methods for this to work. This is somewhat explained in John Chambers "Software for Data Analysis" starting on page 375. That said this system may be very difficult to implement.
A simpler system may be to just add an extra attribute to your data.frame with the extra info you need. For example:
x<-data.frame(a=1:3,b=4:6)
attr(x,"Info")<-"Extra info I need"
attributes(x)$Info
[1] "Extra info I need"
This is not as elegant as a S4 class but will do everything a data.frame does. I suspect that someone who is familiar with S3 classes could improve on this idea quite a bit.
The simplest solution is to have your class contain data.frame instead of having it as one of the slots. For example here is a data.frame with a timestamp:
setclass(
"timestampedDF",
slots=c(timestamp="POSIXt"),
contains="data.frame"
)
Now all functions which work for a data.frame (such as head) will automatically work for timestampedDF objects. If you need to get at the "data frame part", then that is held in a hidden slot object#.Data.

Create a loop for a list of list from RasterBrick in R

I'm on a project in remote sensing running on R. I've got a RasterBrick(x) with the raster for all the dates I'm interested in, a Time Serie with the dates corresponding (called time in the function), and a function which works as I want it when processed manually (z is the pixel I want) :
function(x,z)
{
d<-bfastts(as.vector(x[as.numeric(z)]),time,type="16-day")
n<-bfast(d, h=0.15, season="harmonic", max.iter = 1)
l[[z]]<-list(n$output[[1]]$Tt)
}
The bfastts function is used to create a ts object containing the values of one pixel along the time serie, the bfast is another processing some statisticals of which I only want one result (this is the third line)? None of this two functions are mine, and they are stable and foundable in the R package repository.
So, I would like to add "another level" of function (sorry for my vocabulary which may not be very precise) which would allow to run this function automatically. My expected result would be a list of the result of the function above, so in other words a list of each pixel's time series.
I've tried this (x is still the RasterBrick) :
function(x)
{
z<-nrow(x)*ncol(x)
j<-last(z[[1]])
l<-vector('list',length = j)
index<-function(x)
{
d<-bfastts(as.vector(x[as.numeric(z)]),time,type="16-day")
n<-bfast(d, h=0.15, season="harmonic", max.iter = 1)
l[[z]]<-list(n$output[[1]]$Tt) # this is to add the newly created element to the list
}
lapply(x, FUN='index')
}
but I'm getting an answer that it is not possible to coerce a S4 object to a vector, I guess the problem is in lapply who doesn't like the RasterBrick class... Furthermore I want a list of list in output, and not a list of RasterBrick (I think I understood lapply returns a list of object with the same class as x).
I've tried different workaround, none succesfully, which is not surprising giving my low level in programming, and this one seems to me the closest to what I need. I don't think I fully understand neither how lapply works nor the use of a function in a function.
Thank you very much if you can help me.
Cheers
Guillaume
So, in case it could be useful to someone, here is how I solved this problem (it seems rather very simple finally), the "brick" object is the RasterBrick:
pixelts<- as.list(as.data.frame(t(as.data.frame(brick))))

can I change property of R object

My Ldt1 object has the following property.
> is(Ldt1)
[1] "data.frame" "list" "oldClass" "vector"
I want to change it to data.frame only. How can I do it ?
Edits:
I am answering to question of "why?"
I need to work between two packages. The first package works on different class object and second on different class. In the data manipulation process I have trouble with uncessary class type attached with object giving an error message as:
No method for an object of class genotypeNo method for an object of class factor
You simply cannot. All data.frames are lists and all lists are vectors. (Why would you want to do such a thing anyway?)
Properly written methods will be written to see if the sought-after class is either in the list of the class attribute or in one of its inherited classes. In your case, you (or one of your programs) appear to have made a data input error and turned what you thought should be a numeric vector into a factor vector, or teh designer thought that a factor variable was the logical object to return. It's possible that you could get success by identifying the object or the component and coercing it with 'as.numeric(as.character(facvar))`. (That particular method is a FAQ question.) The better way way forward here is to identify the source of the input or processing error.

Resources