When I have a SpatialPolygonsDataFrame object, I know that I can get to the data two ways:
spatial_df#data$column
spatial_df$column
However I don't understand why the second way is possible. I thought that I must access the data slot using #? Is this something unique about the SpatialPolygonsDataFrame class, or is it something about S4 object in general?
One possible answer is in the sp documentations, which mentions the method [ for the SpatialPolygonsDataFrame class. However, since $ is equivalent to [[, NOT to [, I'm not sure that's the answer.
The short answer is that this behavior of $ is implemented by the Spatial class in the sp package, and is not a feature of general S4 object.
The long answer (how I find out about this):
Use showMethods("$") to find out about all the methods of the generic $.
The result shows:
Function: $ (package base)
x="C++Class"
x="envRefClass"
x="Module"
x="Raster"
x="refObjectGenerator"
x="Spatial"
x="SpatialGDAL"
x="SpatialPoints"
x="SpatialPolygonsDataFrame"
(inherited from: x="Spatial")
So we know that SpatialPolygonsDataFrame-class inherits $ from Spatial-class. We go to the root by:
getMethod("$", "Spatial"), which shows the implementation of $ for Spatial-class as follows:
Method Definition:
function (x, name)
{
if (!("data" %in% slotNames(x)))
stop("no $ method for object without attributes")
x#data[[name]]
}
<environment: namespace:sp>
Therefore, spatial_df$col_name is a shortcut for spatial_df#data[["col_name"]]
Related
lists and environments support the dollar operator in R, so I can do lst$whatever and env$whatever. Other entities, like atomic vectors, do not, for example I can't do vctr$whatever.
Is there a way to programmatically know if a passed entity supports the dollar operator?
having names() apparently is not good, because vectors can have names but are still not dollar indexable. ls() may seem a good approach but it requires that the entity can be converted to an environment, which may not always be the case.
There's no method that will tell you for sure if something will respond to the $ function. But even it there was, there's no guarantee what the $ would do. The $ is generic and classes are free to redefine how it behaves. For example, it could be used to draw a plot
foo <- function(x) {
structure(x, class="foo")
}
`$.foo`<-function(x, v, ...) {
plot(seq.int(nchar(v)), seq.int(nchar(v)), main=v)
}
x <- foo(5)
x$hello
So just because it will respond to $ doesn't mean it will actually return/extract a value.
If you expect $ to have a certain behavior, then you should test for classes that actually have that behavior. If you want to just try to use $, you can always just catch the error in a tryCatch. Here we just return NULL when it fails but you could return whatever you like.
tryCatch(thing$whatever, error=function(e) NULL)
I am trying to access a specific slot from an object inside a list in an R loop:
mysamples<-'a_vcf', 'b_vcf', 'c_vcf'
for(i in mysamples){
vcf<-mget(i)
a<-vcf$i#rowRanges
}
But this is not working:
Error in eval(quote(list(...)), env) :
trying to get slot "rowRanges" from an object of a basic class ("NULL") with no slots
mget() generates a list called vcf which contains an S4 object named i (for example: a_vcf); but, using vcf$iinstead of vcf$a_vcf does not work.
How can I solve this?
You cannot use the $ operator this way - you have to use the [[ operator instead. So if your structure is set up as you describe, that is you have lists called a_vcf, b_vcf, c_vcf, each of which contains an element with the same name, then the following will work:
for(i in mysamples){
vcf <- mget(i)
a <- vcf[[i]]#rowRanges
}
However, please remember you are over-writing a each time, so after the loop completes, you will only have the value of c_vcf$c_vcf#rowRanges written to a.
I am looking for the real object type of some functions in R, for example, I can not find out the object type of mean function.
> library(pryr)
> otype(mean)
[1] "base"
> ftype(mean)
[1] "s3" "generic"
Sometimes the mean function is S3 and sometimes it is base!
What does ftype tell us?
This function figures out whether the input function is a regular/primitive/internal function, a internal/S3/S4 generic, or a S3/S4/RC method. This is function is slightly simplified as it’s possible for a method from one class to be a generic for another class, but that seems like such a bad idea that hopefully no one has done it.
What does otype give us?
Figure out which object system an object belongs to:
• base: no class attribute
• S3: class attribute, but not S4
• S4: isS4, but not RC
• RC: inherits from "refClass"
For reference:
pryr package documentation
R language objects
Is there a function in R that can tell me the attributes of a given object (or class)?
Consider the "dir" function in python when passed the file class:
>>> dir(file)
['__class__', '__delattr__', '__doc__', '__enter__', '__exit__',
'__format__', '__getattribute__', '__hash__', '__init__', '__iter__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__',
'__sizeof__', '__str__', '__subclasshook__', 'close', 'closed',
'encoding', 'errors', 'fileno', 'flush', 'isatty', 'mode', 'name',
'newlines', 'next', 'read', 'readinto', 'readline', 'readlines',
'seek', 'soft space', 'tell', 'truncate', 'write', 'writelines',
'xreadlines']
Maybe there is an equivalent of type as well(?)
>>> type(1)
<type 'int'>
R makes several different object oriented systems available to you, so if you don't know what species of object you're dealing with, you'll first need to determine whether it is one of S3, S4, or RC. Use isS4(x) and is(x, 'refClass') for this. If it's not S4 and not RC, it's S3. See Hadley's Advanced R chapter on object oriented programming for more information.
For S3 and S4 objects there are several functions you need to call to get information equivalent to Python's dir. All of these methods will require you to supply the name of the class of the object as an argument, which you can determine with the class function.
For methods, use methods(class=class(x)) for S3 objects and showMethods(class=class(x)) for S4 objects. To reveal "attribute" names/values, use attributes(x) for S3 objects and getSlots(class(x)) for S4 objects. Note, getSlots will only show the slot names and types, not their values. To access the values, you'll have to use slot, but these values should also print when you simply print the object to the console.
I was hoping to use R's reflection capabilities to intercept the current expression under evaluation before it is evaluated.
For instance, to create some syntax sugar, given the following:
> Server <- setRefClass("Server",
> methods = list(
> handler = function(expr) submitExpressionToRemoteServer(expr)
> )
> )
> server <- Server()
> server$foo$bar$baz #... should be map to... server$handler("foo$bar$baz")
I want the expression server$foo$bar$baz to be intercepted by the server$handlermethod and get mapped to server$handler("foo$bar$baz").
Note that I want this call to succeed even though server$foo is not defined: I am interested only in the expression itself (so I can do stuff with the expression), not that it evaluates to a valid local object.
Is this possible?
I don't think this is possible to redefine the $ behavior with Reference Classes (R5) objects in R. However, this is something that you can do with S4 classes. The main problem is that an expression like
server$foo$bar$baz
would get translated to a series of calls like
$($($(server,"foo"),"bar"),"baz")
but unlike normal function nesting, each inner call appears to be fully evaluated before going to the next level of nesting. This it's not really possible just to split up everything after the first $ because that's not how it's parsed. However you can have the $ function return another object and append all the values sent to the object. Here's a sample S4 class
setClass("Server", slots=list(el="character"))
setMethod("$", signature(x="Server"),
function(x,name) {
xx <- append(slot(x,"el"),name)
new("Server", el=xx)
}
)
server <- new("Server")
server$foo$bar$baz
# An object of class "Server"
# Slot "el":
# [1] "foo" "bar" "baz"
the only problem is there's no way i've found to know when you're at the end of a list if you wanted to do anything with those parameters.