R in Space - About spatial data

April 12, 2018

  R in Space R Spatial

  raster sf sp

David Beauchesne   Marie-Hélène Brice   Nicolas Casajus   Kevin Cazelles   Elliot Dreujou   Steve Vissault  

Spatial data refer to phenomenon or information that can be observed geographically. What a definition! In short spatial data concern every information that could be reported on a map, i.e. on a two-dimensions geographical coordinates system. Two kinds of spatial data exist: vector data and raster data. Generally vectors refer to discrete locations, i.e. objects with boundaries (for instance a city, a road, a country) whereas raster data refer to continuous phenomenon that can be observed everywhere, but without natural boundaries (for instance the surface temperature). Let’s take a look at their characteristics.

Vector data

Vector data consist of the description of a spatially explicit phenomenon geometry (position and coordinates of its boundaries in a specific spatial referential). In addition to this geometry, vector data may contain variables (or attributes) with additional information about the phenomenon at each location. For instance, cities of a country are vector data (points) and attributes could be cities names, population sizes, etc. Borders of a country are also vector data (polygons) and could contain the name of the country, the population for a given year, and the mean number of crimes as attributes.

There are main symbol types for vector data: points, lines and polygons. The geometry of these data structures consists of sets of geographical coordinate pairs (longitude, latitude) in a specific Coordinate Reference System (CRS).

Points data

Points are the simplest vector object. Each point has one two-dimensional coordinates, and several associated variables. For instance, a point might represent a location where an animal was trapped, and the attributes could include the capture date, the size, the sex, and information about the physical environment.

Lines data

Lines are the second type of vector data. A line is a shape consisting of one or several segments (or paths) and each segment has two noteworthy points (or vertex): a starting point and an ending point. Note that the ending point of a segment will have the same coordinates as the starting point of the following segment in the case of a line consisting of connected segments. In other words, a line with one segment is defined by two coordinates pairs (longitude and latitude). A line with two connected segments is defined by three coordinates pairs and a line with two isolated segments is defined by four coordinates pairs. Thus, the representation of a line is very similar to that of a collection of points. The main difference is that the ordering of the points is important, because we need to know which points should be connected two-by-two.

Polygons data

Polygons are closed spatial lines where the coordinates of the starting point of the first segment is identical to the ending point of the last segment. The geometry of a polygon is very similar to that of a line but polygons have three characteristics:

  1. a polygon cannot self-intersect (whereas a line can),

  2. a polygon can contain hole (think about the state of Vatican overlapping the country of Italy but considered as a separated polygon),

  3. as a closed feature, a polygon has an inside and a border.

Vector data are generally stored in ESRI Shapefile, GeoJSON, KML or Simple Features files. In R, two main packages exist to handle spatial vector data: sp and sf. Note that the package rgdal will be used to import/export vector data (go next post to learn more).

Raster data

Raster data are commonly used to represent continuous phenomenon that can be observed everywhere, but without natural boundaries (but with artificial boundaries defined by the user). A raster consists of a grid of equally sized cells (or pixels) that all have a values (or a missing value) for one single variable.

Unlike vector data, the geometry of raster data is not explicitly stored as coordinates. Rather it is implicitly set by setting the spatial extent and the number of rows and columns of a regular grid. From this spatial information, the size of the raster cells (spatial resolution) can be computed. Working with raster data will therefore be more efficient than working with polygons data.

Raster can be used to represent a very broad range of data: continuous (temperature values), discrete (habitat classes) or even binary (species occurrence) variables.

Several file formats exist to store raster data. The most commons are: GeoTIFF, NetCDF, grd and ascii formats. Even the package rgdal can be used to import/export raster data, we will prefer the package raster.

Vector objects in R

In this section we present two packges: sp and sf. The sp package actualy defines classes for both vector and raster objects. Below, we however focus on the vector ones and so we do not detail SpatialGrid and SpatialPixels objects. Also note that sf “[…] aims at succeeding sp in the long term” (Simple Features for R, sf vignette).

Let first create a data frame mydata:

mylon <- -82+2*runif(20)
mylat <- 42+2*runif(20)
mydata <- data.frame(
  lon = mylon,
  lat = mylat,
  var1 = rnorm(20),
  var2 = 10*runif(20)

Let’s have a look at thus data frame:

lon lat var1 var2
-80.26940 42.91336 0.6974238 8.247630
-81.42266 43.81390 0.8289336 4.624590
-81.48951 43.64421 0.8526542 5.935106
-80.99664 42.72651 -1.4177430 7.067949
-80.24332 43.80589 -0.0627814 4.469446
-80.34176 42.85121 -0.3204722 8.863226

Package sp


The table below includes a description of the classes for points, lines and polygons. Basically all these classes work the same way. For instance, in order to define a SpatialPointsDataPoints object, three elements are required: a set of coordinates, a Coordinate Reference System (CRS) and an attribute table. Intermediate class are also defined (for instance points + CRS = SpatialPoints) and the name of the class is also the name of the function to be called.

Classes and functions Contents
Points list of points (set of coordinates)
SpatialPoints list of points + CRS
SpatialPointsDataPoints list of points + CRS + attribute table
Line a line (set of coordinates)
Lines list of lines
SpatialLines list of lines + CRS
SpatialLinesDataFrame list of lines + CRS + attribute table
Polygon a line (set of coordinates)
Polygons list of lines
SpatialPolygons list of lines + CRS
SpatialPolygonsDataFrame list of lines + CRS + attribute table


As an more tangible example, let’s now create a SpatialPointsDataFrame based on our data frame mydata.

mysp <- SpatialPointsDataFrame(
  coords = mydata[, 1:2],
  data = mydata[, 3:4],
  proj4string = CRS(
    "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0"

Note that proj4 is used and we therefore wrote a string that describes the CRS and that proj4 understands. Below are listed some properties of the object we have defined.

#R> [1] TRUE
#R> [1] "SpatialPointsDataFrame"
#R> attr(,"package")
#R> [1] "sp"
#R> [1] "data"        "coords.nrs"  "coords"      "bbox"        "proj4string"
#R> [1] 20  2

Basically, it is a S4 object of class SpatialPointsDataFrame. All slot names refer to attribute that are accessible via and @:

#R> CRS arguments:
#R>  +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs +towgs84=0,0,0
#R>          var1     var2
#R> 1  0.69742380 8.247630
#R> 2  0.82893355 4.624590
#R> 3  0.85265421 5.935106
#R> 4 -1.41774301 7.067949
#R> 5 -0.06278141 4.469446
#R> 6 -0.32047224 8.863226

In order to change projection, the user must call spTransform(), like so:

(mysp2 <- spTransform(mysp, CRS=CRS("+proj=merc +ellps=GRS80")))
#R> class       : SpatialPointsDataFrame 
#R> features    : 20 
#R> extent      : -9122704, -8907835, 5138929, 5415254  (xmin, xmax, ymin, ymax)
#R> coord. ref. : +proj=merc +ellps=GRS80 
#R> variables   : 2
#R> names       :              var1,             var2 
#R> min values  : -2.87145890985463, 1.98925707954913 
#R> max values  :  1.34113296827773,  9.8978210054338

Package sf

Below is a very short overview of classes in sf, the reader that requires further explanation would find more details on the first vignette of sf. Basically three classes are defined: sf, sfc and sfg.

Class sf

pts_sf <- st_as_sf(
  x = mydata,
  coords = c("lon", "lat"),
  crs = 4326)

Let’s examine its class

#R> [1] "sf"         "data.frame"

Class sfc

pts_sfc <- st_geometry(pts_sf)
#R> [1] "sfc_POINT" "sfc"

Class sfg

(x <- st_point(c(1,2)))
#R> [1] "XY"    "POINT" "sfg"

How to import a sp object

st_as_sf() can also be used to convert a sp object into a sf one.

#R> Simple feature collection with 20 features and 2 fields
#R> geometry type:  POINT
#R> dimension:      XY
#R> bbox:           xmin: -81.95064 ymin: 42.04386 xmax: -80.02045 ymax: 43.86695
#R> epsg (SRID):    4326
#R> proj4string:    +proj=longlat +datum=WGS84 +no_defs
#R> First 10 features:
#R>            var1     var2                   geometry
#R> 1   0.697423799 8.247630  POINT (-80.2694 42.91336)
#R> 2   0.828933552 4.624590  POINT (-81.42266 43.8139)
#R> 3   0.852654207 5.935106 POINT (-81.48951 43.64421)
#R> 4  -1.417743011 7.067949 POINT (-80.99664 42.72651)
#R> 5  -0.062781414 4.469446 POINT (-80.24332 43.80589)
#R> 6  -0.320472243 8.863226 POINT (-80.34176 42.85121)
#R> 7  -0.025578147 5.985546  POINT (-81.01205 43.7444)
#R> 8   0.841696775 7.464627 POINT (-80.02045 42.26783)
#R> 9  -0.629140917 6.055168 POINT (-80.43861 42.04386)
#R> 10  0.005685547 9.894143 POINT (-81.70742 42.97536)

Raster objects in R

The R package raster provides three main classes of raster object (more details here):

  1. RasterLayer imports a single-layer (variable) raster,
  2. RasterStack imports in one single object several single-layer (variable) rasters stored in one or different files,
  3. RasterBrick imports in one single object several single-layer (variable) rasters stored in one single file.

Using RasterStack and RasterBrick requires that the geometry of all raster data is equal.

Package raster define three classes of rater object we detail below.


val1 <- matrix(runif(100*100,0,10), ncol = 100, nrow = 100)
ras1 <- raster(
    crs = CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"),
    xmn = -82, xmx = +80, ymn = +42, ymx = +44
#R> [1] "RasterLayer"
#R> attr(,"package")
#R> [1] "raster"
#R> [1] 100 100   1
#R> [1] 1.296941 5.862414 5.656677 6.348071 3.032321 9.118929
#R> [1] "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"

RasterStack and RasterBrick


Let’s first create another raster (with the same CRS)

val2 <- matrix(rnorm(100*100), ncol = 100, nrow = 100)
ras2 <- raster(
    crs = CRS("+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"),
    xmn = -82, xmx = +80, ymn = +42, ymx = +44
#R> [1] "RasterLayer"
#R> attr(,"package")
#R> [1] "raster"

Let’s stack() ras1 and ras2:

sta1 <- stack(ras1, ras2)
#R> [1] "RasterStack"
#R> attr(,"package")
#R> [1] "raster"

Let’s brick() them:

bri1 <- brick(ras1, ras2)
#R> [1] "RasterBrick"
#R> attr(,"package")
#R> [1] "raster"