Vector data

Introduction

The terra package defines a set of classes to represent spatial data. A class defines a particular data type. The data.frame is an example of a class. Any particular data.frame you create is an object (instantiation) of that class.

The main reason for defining classes is to create a standard representation of a particular data type to make it easier to write functions (known as “methods”) for them. See Hadley Wickham’s Advanced R or John Chambers’ Software for data analysis for a detailed discussion of the use of classes in R).

Package terra introduces a number of classes with names that start with Spat. For vector data, the relevant class is SpatVector. These classes represent geometries as well as attributes (variables) describing the geometries.

It is possible to create SpatVector objects from scratch with R code. It can be very useful to create small self contained example to illustrate something, for example to ask a question about how to do a particular operation without needing to give access to the real data you are using (which is always cumbersome). But in real life you will read these from a file or database see Chapter 5.

To get started, let’s make some SpatVector objects from scratch anyway, using the same data as were used in the previous chapter.

Points

longitude <- c(-116.7, -120.4, -116.7, -113.5, -115.5, -120.8, -119.5, -113.7, -113.7, -110.7)
latitude <- c(45.3, 42.6, 38.9, 42.1, 35.7, 38.9, 36.2, 39, 41.6, 36.9)
lonlat <- cbind(longitude, latitude)

Now create a SpatVector object. First load the terra package from the library. If this command fails with Error in library(terra) : there is no package called ‘terra’, then you need to install the package first, with install.packages("terra")

library(terra)
pts <- vect(lonlat)

Let’s check what kind of object pts is.

class (pts)
## [1] "SpatVector"
## attr(,"package")
## [1] "terra"

And what is inside of it

pts
## class       : SpatVector
## geometry    : points
## elements    : 10
## extent      : -120.8, -110.7, 35.7, 45.3  (xmin, xmax, ymin, ymax)
## coord. ref. :
geom(pts)
##    id part      x    y hole
## 1   1    1 -116.7 45.3    0
## 2   2    1 -120.4 42.6    0
## 3   3    1 -116.7 38.9    0
## 4   4    1 -113.5 42.1    0
## 5   5    1 -115.5 35.7    0
## 6   6    1 -120.8 38.9    0
## 7   7    1 -119.5 36.2    0
## 8   8    1 -113.7 39.0    0
## 9   9    1 -113.7 41.6    0
## 10 10    1 -110.7 36.9    0

So we see that the object has the coordinates we supplied, but also an extent. This spatial extent was computed from the coordinates. There is also a coordinate reference system (“crs”, discussed in more detail later). We did not provide the crs so it is unknown (NA). That is not good, so let’s recreate the object, and now provide a crs.

crdref <- "+proj=longlat +datum=WGS84"
pts <- vect(lonlat, crs=crdref)
pts
## class       : SpatVector
## geometry    : points
## elements    : 10
## extent      : -120.8, -110.7, 35.7, 45.3  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84
crs(pts)
## [1] "+proj=longlat +datum=WGS84"

We can add attributes (variables) to the SpatVector object. First we need a data.frame with the same number of rows as there are geometries.

# Generate random precipitation values, same quantity as points
precipvalue <- runif(nrow(lonlat), min=0, max=100)
df <- data.frame(ID=1:nrow(lonlat), precip=precipvalue)

Combine the SpatVector with the data.frame.

ptsdf <- vect(lonlat, data=df)
crs(ptsdf) <- crdref
ptsdf
## class       : SpatVector
## geometry    : points
## elements    : 10
## extent      : -120.8, -110.7, 35.7, 45.3  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84

To see what is inside:

show(ptsdf)
## class       : SpatVector
## geometry    : points
## elements    : 10
## extent      : -120.8, -110.7, 35.7, 45.3  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84

Lines and polygons

Making a SpatVector of points was easy. Making a SpatVector of lines or polygons is a bit more complex, but stil relatively straightforward.

lon <- c(-116.8, -114.2, -112.9, -111.9, -114.2, -115.4, -117.7)
lat <- c(41.3, 42.9, 42.4, 39.8, 37.6, 38.3, 37.6)
lonlat <- cbind(id=1, part=1, lon, lat)
lns <- vect(lonlat, type="lines", crs=crdref)
lns
## class       : SpatVector
## geometry    : lines
## elements    : 1
## extent      : -117.7, -111.9, 37.6, 42.9  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84
pols <- vect(lonlat, type="polygons", crs=crdref)
pols
## class       : SpatVector
## geometry    : polygons
## elements    : 1
## extent      : -117.7, -111.9, 37.6, 42.9  (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84

Behind the scenes the class deals with the complexity of accommodate the possibility of multiple polygons, each consisting of multiple sub-polygons, some of which may be “holes”. Fortunately, you do not need to understand how these structures are organized. The main take home message is that a SpatVector stores geometries (coordinates), the name of the coordinate reference system, and attributes.

We can make use plot to make a map.

plot(pols, las=1)
plot(pols, border='blue', col='yellow', lwd=3, add=TRUE)
points(pts, col='red', pch=20, cex=3)

image0

We’ll make more fancy maps later.