To work efficiently with the SpatialPolygonsDataFrame
(SPDF) objects used in the MazamaSpatialUtils package, it is important to understand the S4 object classes that make up the sp package. This vignette introduces simple concepts associated with R’s object classes so that newcomers to this style of coding can work efficiently with SPDFs.
Unlike C, Java or python, R is a proudly “functional language”. The basic element is a function rather than an object. Over the years, various object systems have been developed for R and these are concisely explained in the Object Oriented Programming chapter from Wickham’s Advanced R.
We will discuss on S3 and S4 objects with a focus on how to tell which is which and how to manipulate them.
When programming in R (as opposed to scripting), it is important to understand the fundamental nature of the “things” you are working with. The most common type of “thing” is an object of type S3. We will start by investigating a familiar function and its return value and learn the following:
class
attribute determines how “methods are dispatched”# Plot a histogram but save the return value
hist(rnorm(100), plot = FALSE)
h <-
# Query this 'object'
typeof(h)
## [1] "list"
class(h)
## [1] "histogram"
attributes(h)
## $names
## [1] "breaks" "counts" "density" "mids" "xname" "equidist"
##
## $class
## [1] "histogram"
names(h)
## [1] "breaks" "counts" "density" "mids" "xname" "equidist"
OK. So h
has an internal storage type (typeof()
) of list
; and a class
attribute of histogram
. A simpler way to state this would be to say that “h
is a list of class histogram
.”
You can access elements of this object in normal “list” fashion:
# What types of elements do we have?
str(lapply(h, class))
## List of 6
## $ breaks : chr "numeric"
## $ counts : chr "integer"
## $ density : chr "numeric"
## $ mids : chr "numeric"
## $ xname : chr "character"
## $ equidist: chr "logical"
# Let's look a "counts"
$counts h
## [1] 1 3 4 21 16 25 12 11 5 1 1
# Or, alternatively
"counts"]] h[[
## [1] 1 3 4 21 16 25 12 11 5 1 1
Let’s examine how R creates different plots for different types of “things”.
# Lets set up some more "objects"
1:10 # Numbers 1-10
h1 <-
layout(matrix(seq(2)))
plot(h)
plot(h1)
layout(1)
This capability demonstrates something called “method dispatch” where a top level function assess the class of an S3 object and calls the appropriate sub-function.
class(h)
## [1] "histogram"
class(h1)
## [1] "integer"
methods("plot")
## [1] plot,ANY,ANY-method
## [2] plot,Spatial,missing-method
## [3] plot,SpatialCollections,missing-method
## [4] plot,SpatialGrid,missing-method
## [5] plot,SpatialGridDataFrame,missing-method
## [6] plot,SpatialLines,missing-method
## [7] plot,SpatialMultiPoints,missing-method
## [8] plot,SpatialPixels,missing-method
## [9] plot,SpatialPixelsDataFrame,missing-method
## [10] plot,SpatialPoints,missing-method
## [11] plot,SpatialPolygons,missing-method
## [12] plot,SpatialRings,missing-method
## [13] plot,gpc.poly,ANY-method
## [14] plot.HoltWinters*
## [15] plot.TukeyHSD*
## [16] plot.acf*
## [17] plot.data.frame*
## [18] plot.decomposed.ts*
## [19] plot.default
## [20] plot.dendrogram*
## [21] plot.density*
## [22] plot.ecdf
## [23] plot.factor*
## [24] plot.formula*
## [25] plot.function
## [26] plot.hclust*
## [27] plot.histogram*
## [28] plot.isoreg*
## [29] plot.lm*
## [30] plot.medpolish*
## [31] plot.mlm*
## [32] plot.ppr*
## [33] plot.prcomp*
## [34] plot.princomp*
## [35] plot.profile.nls*
## [36] plot.raster*
## [37] plot.shingle*
## [38] plot.spec*
## [39] plot.stepfun
## [40] plot.stl*
## [41] plot.table*
## [42] plot.trellis*
## [43] plot.ts
## [44] plot.tskernel*
## see '?methods' for accessing help and source code
It turns out there are lots of “plot” functions. If you try to plot an object of class histogram
you will end up calling plot.histogram
whereas plotting an object of class integer
ends up calling plot.default
.
While S3 objects are simple, they do no allow many of the fancier features associated with “Object Oriented Programming” (OOP). As R evolved, people came up with S4 objects to address this. We won’t go into the details about what is possible but just point out how to use S4 objects from the sp package.
@
The MazamaSpatialUtils package uses sp and creates S4 objects:
# Load the 'SimpleCountries' dataset
library(MazamaSpatialUtils)
data("SimpleCountries")
class(SimpleCountries)
## [1] "SpatialPolygonsDataFrame"
## attr(,"package")
## [1] "sp"
typeof(SimpleCountries)
## [1] "S4"
# It's big so we don't just print out the attributes
attributes(SimpleCountries)
a <-class(a)
## [1] "list"
names(a)
## [1] "data" "polygons" "plotOrder" "bbox" "proj4string"
## [6] "class"
# S4 objects have 'slots'
slotNames(SimpleCountries)
## [1] "data" "polygons" "plotOrder" "bbox" "proj4string"
# Access slots using 'slot()' or '@'
class(slot(SimpleCountries, "data"))
## [1] "data.frame"
class(SimpleCountries@data)
## [1] "data.frame"
Each SpatialPolygonsDataFrame
is an S4 object with a 1:1 relationship between records (rows) in the @data
dataframe and Polygons
S4 objects in the @polygons
list. This makes it possible to use some functions like subset()
that work on dataframes. The following code shows how to work with them.
# Compare 'data' and 'polygons' slots
nrow(SimpleCountries@data)
## [1] 246
length(SimpleCountries@polygons)
## [1] 246
# Look at the first record
str(SimpleCountries@data[1,])
## 'data.frame': 1 obs. of 6 variables:
## $ countryCode: chr "AG"
## $ countryName: chr "Antigua and Barbuda"
## $ ISO3 : chr "ATG"
## $ FIPS : chr "AC"
## $ UN_region : int 19
## $ polygonID : chr "AG"
# We can also use normal dataframe syntax to access columns of data
$countryName[1] SimpleCountries
## [1] "Antigua and Barbuda"
# Magic happens when we plot using normal dataframe syntax
plot(SimpleCountries[1,])
# Here is a more advanced example using pipes
%>%
SimpleCountries subset(UN_region == 150) %>%
subset(countryCode != "RU") %>%
plot()
%>%
SimpleCountries subset(countryCode %in% c("DE", "AT", "CH")) %>%
plot(col = 'red', add = TRUE)
title("German Speakers in Europe")
Best of luck making interesting maps!
Mazama Science