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 for
examples.
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)
## terra version 1.0.10
##
## Attaching package: 'terra'
## The following object is masked from 'package:knitr':
##
## spin
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
## dimensions : 10, 0 (geometries, attributes)
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## coord. ref. :
geom(pts)
## geom 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 cis when we created pts
so it is
unknown. 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
## dimensions : 10, 0 (geometries, attributes)
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
crs(pts)
## [1] "GEOGCRS[\"unknown\",\n DATUM[\"World Geodetic System 1984\",\n ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n LENGTHUNIT[\"metre\",1]],\n ID[\"EPSG\",6326]],\n PRIMEM[\"Greenwich\",0,\n ANGLEUNIT[\"degree\",0.0174532925199433],\n ID[\"EPSG\",8901]],\n CS[ellipsoidal,2],\n AXIS[\"longitude\",east,\n ORDER[1],\n ANGLEUNIT[\"degree\",0.0174532925199433,\n ID[\"EPSG\",9122]]],\n AXIS[\"latitude\",north,\n ORDER[2],\n ANGLEUNIT[\"degree\",0.0174532925199433,\n ID[\"EPSG\",9122]]]]"
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
## dimensions : 10, 0 (geometries, attributes)
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
To see what is inside:
ptsdf
## class : SpatVector
## geometry : points
## dimensions : 10, 0 (geometries, attributes)
## extent : -120.8, -110.7, 35.7, 45.3 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
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
## dimensions : 1, 0 (geometries, attributes)
## extent : -117.7, -111.9, 37.6, 42.9 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
pols <- vect(lonlat, type="polygons", crs=crdref)
pols
## class : SpatVector
## geometry : polygons
## dimensions : 1, 0 (geometries, attributes)
## extent : -117.7, -111.9, 37.6, 42.9 (xmin, xmax, ymin, ymax)
## coord. ref. : +proj=longlat +datum=WGS84 +no_defs
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)
We’ll make more fancy maps later.