Getting a slot's value of S4 objects?
Asked Answered
R

2

10

So I have a spatialpolygons object in R; but I am not sure why I am unable to retrieve the "area" slot from it.

Here's my R session:

> spatialpolygons
An object of class "SpatialPolygons"
Slot "polygons":
[[1]]
An object of class "Polygons"
Slot "Polygons":
[[1]]
An object of class "Polygon"
Slot "labpt":
[1] 20.50516 57.72918

Slot "area":
[1] 36.85484

Slot "hole":
[1] FALSE

Slot "ringDir":
[1] 1

Slot "coords":
         [,1]     [,2]
[1,] 16.48438 59.73633
[2,] 22.59277 61.14258
[3,] 24.74609 55.03418
[4,] 17.49512 55.12207
[5,] 16.48438 59.73633



Slot "plotOrder":
[1] 1

Slot "labpt":
[1] 20.50516 57.72918

Slot "ID":
[1] "myMultiPolygons"

Slot "area":
[1] 36.85484



Slot "plotOrder":
[1] 1

Slot "bbox":
       min      max
x 16.48438 24.74609
y 55.03418 61.14258

Slot "proj4string":
CRS arguments:
 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 

> spatialpolygons@bbox
       min      max
x 16.48438 24.74609
y 55.03418 61.14258
> spatialpolygons@area
Error: no slot of name "area" for this object of class "SpatialPolygons"
> slotNames(spatialpolygons)
[1] "polygons"    "plotOrder"   "bbox"        "proj4string"
> names(spatialpolygons)
[1] "myMultiPolygons"
Redwing answered 3/1, 2012 at 6:26 Comment(0)
P
19

First off, you should be aware that the @area slot is not a reliable source of information about a SpatialPolygons* object's actual area. As noted in ?"Polygons-class", the @area slot is just used as an adjunct to plotting (preventing smaller polygons from getting painted over by larger ones) and does not respect projection or properly account for holes in polygons.

To get accurate areas, you should instead use rgeos::gArea() for layers with projected coordinate reference systems or geosphere::areaPolygon() for those in lat-long coordinate reference systems (i.e. CRS(+proj=longlat)).

With those caveats out of the way, the following shows how you can get the contents of the @area slots if you do in fact want them.


The main complication is that the area slot belongs to the Polygon object, not to the SpatialPolygons object (of which the Polygon object is one element). You thus need to first dig down into the SpatialPolygons object to extract to the individual Polygon object(s).

One you have done that, you can just use the @ operator to extract the contents of the area slot.

The following example uses the SpatialPolygons object created in Section 7 of the sp package vignette (warning, pdf):

require(sp)
# Example pasted in from Section 7 of the sp vignette
Sr1 = Polygon(cbind(c(2,4,4,1,2),c(2,3,5,4,2)))
Sr2 = Polygon(cbind(c(5,4,2,5),c(2,3,2,2)))
Sr3 = Polygon(cbind(c(4,4,5,10,4),c(5,3,2,5,5)))
Sr4 = Polygon(cbind(c(5,6,6,5,5),c(4,4,3,3,4)), hole = TRUE)
Srs1 = Polygons(list(Sr1), "s1")
Srs2 = Polygons(list(Sr2), "s2")
Srs3 = Polygons(list(Sr3, Sr4), "s3/4")
SpP = SpatialPolygons(list(Srs1,Srs2,Srs3), 1:3)

# To extract the area of the first (or in your case only) Polygon
SpP@polygons[[1]]@area
# [1] 5.5

# Extract the areas of all three component Polygons
sapply(SpP@polygons, function(x) x@area)
# [1]  5.5  1.5 10.0

## For areas, rgeos::gArea() or geosphere::areaPolygons() are generally more appropriate
## (Note, for instance, that it properly accounts for the hole in the 3rd polygon.)
rgeos::gArea(SpP, byid=TRUE)
#  s1   s2 s3/4 
# 5.5  1.5  9.0 
Paperboard answered 3/1, 2012 at 6:45 Comment(7)
so for my case where there is only 1 polygon, spatialpolygons@polygons[[1]]@area works.Redwing
Exactly, and glad it worked for you. I'll add that to the answer for completeness.Dissatisfy
Just for fun, this would also work: slot(slot(Sp, "polygons")[[1]], "area"). :) You can also check for slot names with slotNames.Intercontinental
@JoshO'Brien ?sapply states that: "Users of S4 classes should pass a list to lapply and vapply..." Better to use lapply or vapply.Studious
@imanuelc -- Interesting catch, but I think you're parsing that incorrectly. At least I read it to mean "if you are using S4 classes with lapply or vapply, best to pass them in as a list (because both those functions call as.list(), which might alter your object in unexpected ways)." (sapply doesn't call as.list(), so there is no such admonition.)Dissatisfy
+1. What about the slot 'coords'? I could not retrieve those, though.Crispate
@AndreSilva -- The coordinates are one more level down into the structure, so you have to do something like sapply(SpP@polygons, function(x) coordinates(x@Polygons[[1]])). (These sp objects, while well-designed in some aspects, turn out to be not very user-friendly, at least when you're first getting started with 'em!)Dissatisfy
O
8

You can calculate area with functions in the rgeos package, examples below using Josh's example data. This might be more appropriate since the area slot is merely for plotting.

library(rgeos)
gArea(SpP[1,])
## [1] 5.5
gArea(SpP[2,])
##[1] 1.5
gArea(SpP[3,])
## [1] 10

All at once:

gArea(SpP)
[1] 17

The coordinate system in use should be considered, this is just raw geometric area.

The help pages discuss the area slot.

?gArea
....

Note that this value may be different from the ‘area’ slot of the ‘Polygons’ class as this value does not subtract the area of any holes in the geometry.

?"Polygons-class"
...

‘area’: Object of class ‘"numeric"’; the gross total planar area of the Polygon list but not double-counting holes (changed from 0.9-58 - islands are summed, holes are ignored rather than subtracted); these values are used to make sure that polygons of a smaller area are plotted after polygons of a larger area, does not respect projection as objects of this class have no projection defined

Outoftheway answered 3/1, 2012 at 8:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.