roopmethodsr-maptools

How to tell what method is being used by a function call when `methods` fails?


Might as well let the cat out of the bag and say that I have been trying for about a day to figure out what is happening when I call plot for an object of class SpatialPolygons*. My instinct is to look for plot.SpatialPolygonsDataFrame, the approach which works for any number of other examples I've seen & encountered, but this failed.

Quick example:

US States .shp file here.

library(maptools)
us.states<-readShapePoly("cb_2014_us_state_5m.shp")
plot(us.states)

A sample plot. It shows the polygons of all the US states and territories placed on an invisible globe. It's hard to read, but the plot is not the main thing for this question.

A bit dumpy but whatever--the point is that a simple call to plot and somewhere deep down R knew which method to call in order to give us a representation of all the shapes.

After searching around a bit, I tried two of the other approaches suggested by various SO Q&As, first and foremost:

> methods(plot)
 [1] plot.aareg*                         plot.acf*                          
 [3] plot,ANY,ANY-method                 plot.cox.zph*                      
 [5] plot.data.frame*                    plot.decomposed.ts*                
 [7] plot.default                        plot.dendrogram*                   
 [9] plot.density*                       plot.ecdf                          
[11] plot.factor*                        plot.formula*                      
[13] plot.function                       plot.hclust*                       
[15] plot.histogram*                     plot.HoltWinters*                  
[17] plot.isoreg*                        plot.lm*                           
[19] plot.medpolish*                     plot.mlm*                          
[21] plot.ppr*                           plot.prcomp*                       
[23] plot.princomp*                      plot.profile.nls*                  
[25] plot.raster*                        plot.shingle*                      
[27] plot,SpatialGrid,missing-method     plot,SpatialLines,missing-method   
[29] plot,Spatial,missing-method         plot,SpatialPixels,missing-method  
[31] plot,SpatialPoints,missing-method   plot,SpatialPolygons,missing-method
[33] plot.spec*                          plot.spline*                       
[35] plot.stepfun                        plot.stl*                          
[37] plot.survfit*                       plot.table*                        
[39] plot.times*                         plot.trellis*                      
[41] plot.ts                             plot.tskernel*                     
[43] plot.TukeyHSD*                      plot.xyVector*                     
[45] plot.zoo*                              

The answer would appear to be in slots 27-32; however, each is followed by a vexing comma! No mention that this is possible in ?methods and ?plot,SpatialPolygons,missing-method is an error. A quick search for missing-method turns up nothing of use and there's again no mention in ?methods.

OK; moving on. What about getS3method? getMethod? getMethods? getAllMethods??

> getS3method("plot","SpatialPolygonsDataFrame")
Error in getS3method("plot", "SpatialPolygonsDataFrame") : 
  S3 method 'plot.SpatialPolygonsDataFrame' not found

> getMethod("plot","SpatialPolygonsDataFrame")
Error in getMethod("plot", "SpatialPolygonsDataFrame") : 
  no method found for function 'plot' and signature SpatialPolygonsDataFrame

The latter two are deprecated & also return nothing.

So apparently these functions are just a stand-in for my first instincts.

So now what? How can I tell which method is being called by plot when it is passed a SpatialPolygonsDataFrame? Is there any general approach to this problem that supersedes the approach I used above?

Edit:

Sort of by accident I stumbled upon this (=?`Spatial-Polygons-class` ) which says:

The plot method for spatial polygons takes the following arguments:

but it still doesn't say what that method is, exactly.


Solution

  • To answer a couple of questions raised by Gregor. The methods function did not formerly display results for S4-methods, but now it does. Doing a search in the NEWS document I see this was added with version 3.2.0:

    methods() reports S4 in addition to S3 methods; output is simplified when the class 
    argument is used. .S3methods() and methods::.S4methods() report S3 and S4 methods separately.
    

    SpatialPolygons are S4 objects, and so have slots and S4-methods that are dispatched. You can display an S4 method with:

    showMethods(f='plot', classes='SpatialPolygons', includeDefs=TRUE)
    #    ---- result ---
    Function: plot (package graphics)
    x="SpatialPolygons", y="missing"
    function (x, y, ...) 
    plot.SpatialPolygons(x, ...)
    

    That tells you that there is an S4 function for that class. You can execute either sp:::SpatialPolygons or getAnywhere(plot.SpatialPolygons) to see the function code. (Often that call using includeDefs=TRUE would display the R-code, but not here.) The result for methods(plot) when package 'sp' is loaded tell you that there are 8 different plot S4 methods registered in the workspace. The items following the commas are the "signatures" that are used for function dispatch. "missing-method" refers to situations where the second argument is not specified, wherein the missing function executed inside a function body would return TRUE:

      [1] plot,ANY,ANY-method                 plot,color,ANY-method              
      [3] plot,Spatial,missing-method         plot,SpatialGrid,missing-method    
      [5] plot,SpatialLines,missing-method    plot,SpatialPixels,missing-method  
      [7] plot,SpatialPoints,missing-method   plot,SpatialPolygons,missing-method
    

    This will show you what then gets used to dispatch a plot-call when the the object passed to it does not match any of the S4 methods:

    showMethods(f='plot', classes='ANY', includeDefs=TRUE)
    Function: plot (package graphics)
    x="ANY", y="ANY"
    function (x, y, ...) 
    UseMethod("plot")
    
    
    x="color", y="ANY"
    function (x, y, ...) 
    {
        .local <- function (x, y, pch = 20, cex = 3) 
        pairs(coords(x), col = hex(x, fix = TRUE), pch = pch, cex = cex)
        .local(x, y, ...)
    }
    

    Basically the R interpreter first checks to see if any S4 methods are appropriate, and failing that, will start going through the S3 methods until it gets to plot.default.

    > getMethod(f='plot', signature=c(x='SpatialPolygons', y='missing'))
    Method Definition:
    
    function (x, y, ...) 
    plot.SpatialPolygons(x, ...)
    <environment: namespace:sp>
    
    Signatures:
            x                 y        
    target  "SpatialPolygons" "missing"
    defined "SpatialPolygons" "missing"
    

    And BTW I see this in the response from ?getMethods:

    ## Deprecated in 2010 and defunct in 2015 for \code{table = FALSE}:
    getMethods(f, where, table = FALSE)