--- title: "Working with Spatial Data" --- [ The R Script associated with this page is available here](scripts/04_Spatial.R). Download this file and open it (or copy-paste into a new script) with RStudio so you can follow along. # Setup ## Load packages ```r library(sp) library(rgdal) library(ggplot2) library(dplyr) library(tidyr) library(maptools) ``` # Point data ## Generate some random data ```r coords = data.frame( x=rnorm(100), y=rnorm(100) ) str(coords) ``` ``` ## 'data.frame': 100 obs. of 2 variables: ## $ x: num -1.569 0.247 0.839 0.703 -1.147 ... ## $ y: num 0.1952 0.0851 -2.2198 -0.3312 -0.7096 ... ``` ```r plot(coords) ```  ## Convert to `SpatialPoints` ```r sp = SpatialPoints(coords) str(sp) ``` ``` ## Formal class 'SpatialPoints' [package "sp"] with 3 slots ## ..@ coords : num [1:100, 1:2] -1.569 0.247 0.839 0.703 -1.147 ... ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : NULL ## .. .. ..$ : chr [1:2] "x" "y" ## ..@ bbox : num [1:2, 1:2] -2.29 -2.69 3.41 2.68 ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : chr [1:2] "x" "y" ## .. .. ..$ : chr [1:2] "min" "max" ## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot ## .. .. ..@ projargs: chr NA ``` ## Create a `SpatialPointsDataFrame` First generate a dataframe (analagous to the _attribute table_ in a shapefile) ```r data=data.frame(ID=1:100,group=letters[1:20]) head(data) ``` ``` ## ID group ## 1 1 a ## 2 2 b ## 3 3 c ## 4 4 d ## 5 5 e ## 6 6 f ``` Combine the coordinates with the data ```r spdf = SpatialPointsDataFrame(coords, data) spdf = SpatialPointsDataFrame(sp, data) str(spdf) ``` ``` ## Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots ## ..@ data :'data.frame': 100 obs. of 2 variables: ## .. ..$ ID : int [1:100] 1 2 3 4 5 6 7 8 9 10 ... ## .. ..$ group: Factor w/ 20 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ... ## ..@ coords.nrs : num(0) ## ..@ coords : num [1:100, 1:2] -1.569 0.247 0.839 0.703 -1.147 ... ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : NULL ## .. .. ..$ : chr [1:2] "x" "y" ## ..@ bbox : num [1:2, 1:2] -2.29 -2.69 3.41 2.68 ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : chr [1:2] "x" "y" ## .. .. ..$ : chr [1:2] "min" "max" ## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot ## .. .. ..@ projargs: chr NA ``` Note the use of _slots_ designated with a `@`. See `?slot` for more. ## Promote a data frame with `coordinates()` ```r coordinates(data) = cbind(coords$x, coords$y) ``` ```r str(spdf) ``` ``` ## Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots ## ..@ data :'data.frame': 100 obs. of 2 variables: ## .. ..$ ID : int [1:100] 1 2 3 4 5 6 7 8 9 10 ... ## .. ..$ group: Factor w/ 20 levels "a","b","c","d",..: 1 2 3 4 5 6 7 8 9 10 ... ## ..@ coords.nrs : num(0) ## ..@ coords : num [1:100, 1:2] -1.569 0.247 0.839 0.703 -1.147 ... ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : NULL ## .. .. ..$ : chr [1:2] "x" "y" ## ..@ bbox : num [1:2, 1:2] -2.29 -2.69 3.41 2.68 ## .. ..- attr(*, "dimnames")=List of 2 ## .. .. ..$ : chr [1:2] "x" "y" ## .. .. ..$ : chr [1:2] "min" "max" ## ..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot ## .. .. ..@ projargs: chr NA ``` ## Subset data ```r subset(spdf, group=="a") ``` ``` ## class : SpatialPointsDataFrame ## features : 5 ## extent : -1.56881, 1.961121, -1.717863, 0.2500004 (xmin, xmax, ymin, ymax) ## coord. ref. : NA ## variables : 2 ## names : ID, group ## min values : 1, a ## max values : 81, a ``` Or using `[]` ```r spdf[spdf$group=="a",] ``` ``` ## class : SpatialPointsDataFrame ## features : 5 ## extent : -1.56881, 1.961121, -1.717863, 0.2500004 (xmin, xmax, ymin, ymax) ## coord. ref. : NA ## variables : 2 ## names : ID, group ## min values : 1, a ## max values : 81, a ``` Unfortunately, `dplyr` functions do not directly filter spatial objects.
### Issues
* Multipart Polygons
* Holes
Rarely construct _by hand_...
# Importing data
But, you rarely construct data _from scratch_ like we did above. Usually you will import datasets created elsewhere.
## Geospatial Data Abstraction Library ([GDAL](gdal.org))
`rgdal` package for importing/exporting/manipulating spatial data:
* `readOGR()` and `writeOGR()`: Vector data
* `readGDAL()` and `writeGDAL()`: Raster data
Also the `gdalUtils` package for reprojecting, transforming, reclassifying, etc.
List the file formats that your installation of rgdal can read/write with `ogrDrivers()`:
name long_name write copy isVector
--------------- ---------------------------------------------------- ------ ------ ---------
AeronavFAA Aeronav FAA FALSE FALSE TRUE
AmigoCloud AmigoCloud TRUE FALSE TRUE
ARCGEN Arc/Info Generate FALSE FALSE TRUE
AVCBin Arc/Info Binary Coverage FALSE FALSE TRUE
AVCE00 Arc/Info E00 (ASCII) Coverage FALSE FALSE TRUE
BNA Atlas BNA TRUE FALSE TRUE
Carto Carto TRUE FALSE TRUE
Cloudant Cloudant / CouchDB TRUE FALSE TRUE
CouchDB CouchDB / GeoCouch TRUE FALSE TRUE
CSV Comma Separated Value (.csv) TRUE FALSE TRUE
CSW OGC CSW (Catalog Service for the Web) FALSE FALSE TRUE
DGN Microstation DGN TRUE FALSE TRUE
DXF AutoCAD DXF TRUE FALSE TRUE
EDIGEO French EDIGEO exchange format FALSE FALSE TRUE
ElasticSearch Elastic Search TRUE FALSE TRUE
ESRI Shapefile ESRI Shapefile TRUE FALSE TRUE
Geoconcept Geoconcept TRUE FALSE TRUE
GeoJSON GeoJSON TRUE FALSE TRUE
GeoRSS GeoRSS TRUE FALSE TRUE
GFT Google Fusion Tables TRUE FALSE TRUE
GML Geography Markup Language (GML) TRUE FALSE TRUE
GPKG GeoPackage TRUE TRUE TRUE
GPSBabel GPSBabel TRUE FALSE TRUE
GPSTrackMaker GPSTrackMaker TRUE FALSE TRUE
GPX GPX TRUE FALSE TRUE
HTF Hydrographic Transfer Vector FALSE FALSE TRUE
HTTP HTTP Fetching Wrapper FALSE FALSE TRUE
Idrisi Idrisi Vector (.vct) FALSE FALSE TRUE
JML OpenJUMP JML TRUE FALSE TRUE
KML Keyhole Markup Language (KML) TRUE FALSE TRUE
MapInfo File MapInfo File TRUE FALSE TRUE
Memory Memory TRUE FALSE TRUE
netCDF Network Common Data Format TRUE TRUE TRUE
ODS Open Document/ LibreOffice / OpenOffice Spreadsheet TRUE FALSE TRUE
OGR_GMT GMT ASCII Vectors (.gmt) TRUE FALSE TRUE
OGR_PDS Planetary Data Systems TABLE FALSE FALSE TRUE
OGR_SDTS SDTS FALSE FALSE TRUE
OGR_VRT VRT - Virtual Datasource FALSE FALSE TRUE
OpenAir OpenAir FALSE FALSE TRUE
OpenFileGDB ESRI FileGDB FALSE FALSE TRUE
OSM OpenStreetMap XML and PBF FALSE FALSE TRUE
PCIDSK PCIDSK Database File TRUE FALSE TRUE
PDF Geospatial PDF TRUE TRUE TRUE
PGDUMP PostgreSQL SQL dump TRUE FALSE TRUE
PLSCENES Planet Labs Scenes API FALSE FALSE TRUE
REC EPIInfo .REC FALSE FALSE TRUE
S57 IHO S-57 (ENC) TRUE FALSE TRUE
SEGUKOOA SEG-P1 / UKOOA P1/90 FALSE FALSE TRUE
SEGY SEG-Y FALSE FALSE TRUE
Selafin Selafin TRUE FALSE TRUE
SQLite SQLite / Spatialite TRUE FALSE TRUE
SUA Tim Newport-Peace's Special Use Airspace Format FALSE FALSE TRUE
SVG Scalable Vector Graphics FALSE FALSE TRUE
SXF Storage and eXchange Format FALSE FALSE TRUE
TIGER U.S. Census TIGER/Line TRUE FALSE TRUE
UK .NTF UK .NTF FALSE FALSE TRUE
VDV VDV-451/VDV-452/INTREST Data Format TRUE FALSE TRUE
VFK Czech Cadastral Exchange Data Format FALSE FALSE TRUE
WAsP WAsP .map format TRUE FALSE TRUE
WFS OGC WFS (Web Feature Service) FALSE FALSE TRUE
XLSX MS Office Open XML spreadsheet TRUE FALSE TRUE
XPlane X-Plane/Flightgear aeronautical data FALSE FALSE TRUE
Now as an example, let's read in a shapefile that's included in the `maptools` package. You can try
```r
## get the file path to the files
file=system.file("shapes/sids.shp", package="maptools")
## get information before importing the data
ogrInfo(dsn=file, layer="sids")
```
```
## Source: "/Library/Frameworks/R.framework/Versions/3.4/Resources/library/maptools/shapes/sids.shp", layer: "sids"
## Driver: ESRI Shapefile; number of rows: 100
## Feature type: wkbPolygon with 2 dimensions
## Extent: (-84.32385 33.88199) - (-75.45698 36.58965)
## LDID: 87
## Number of fields: 14
## name type length typeName
## 1 AREA 2 12 Real
## 2 PERIMETER 2 12 Real
## 3 CNTY_ 12 11 Integer64
## 4 CNTY_ID 12 11 Integer64
## 5 NAME 4 32 String
## 6 FIPS 4 5 String
## 7 FIPSNO 12 16 Integer64
## 8 CRESS_ID 0 3 Integer
## 9 BIR74 2 12 Real
## 10 SID74 2 9 Real
## 11 NWBIR74 2 11 Real
## 12 BIR79 2 12 Real
## 13 SID79 2 9 Real
## 14 NWBIR79 2 12 Real
```
```r
## Import the data
sids <- readOGR(dsn=file, layer="sids")
```
```
## OGR data source with driver: ESRI Shapefile
## Source: "/Library/Frameworks/R.framework/Versions/3.4/Resources/library/maptools/shapes/sids.shp", layer: "sids"
## with 100 features
## It has 14 fields
## Integer64 fields read as strings: CNTY_ CNTY_ID FIPSNO
```
```r
summary(sids)
```
```
## Object of class SpatialPolygonsDataFrame
## Coordinates:
## min max
## x -84.32385 -75.45698
## y 33.88199 36.58965
## Is projected: NA
## proj4string : [NA]
## Data attributes:
## AREA PERIMETER CNTY_ CNTY_ID NAME
## Min. :0.0420 Min. :0.999 1825 : 1 1825 : 1 Alamance : 1
## 1st Qu.:0.0910 1st Qu.:1.324 1827 : 1 1827 : 1 Alexander: 1
## Median :0.1205 Median :1.609 1828 : 1 1828 : 1 Alleghany: 1
## Mean :0.1263 Mean :1.673 1831 : 1 1831 : 1 Anson : 1
## 3rd Qu.:0.1542 3rd Qu.:1.859 1832 : 1 1832 : 1 Ashe : 1
## Max. :0.2410 Max. :3.640 1833 : 1 1833 : 1 Avery : 1
## (Other):94 (Other):94 (Other) :94
## FIPS FIPSNO CRESS_ID BIR74
## 37001 : 1 37001 : 1 Min. : 1.00 Min. : 248
## 37003 : 1 37003 : 1 1st Qu.: 25.75 1st Qu.: 1077
## 37005 : 1 37005 : 1 Median : 50.50 Median : 2180
## 37007 : 1 37007 : 1 Mean : 50.50 Mean : 3300
## 37009 : 1 37009 : 1 3rd Qu.: 75.25 3rd Qu.: 3936
## 37011 : 1 37011 : 1 Max. :100.00 Max. :21588
## (Other):94 (Other):94
## SID74 NWBIR74 BIR79 SID79
## Min. : 0.00 Min. : 1.0 Min. : 319 Min. : 0.00
## 1st Qu.: 2.00 1st Qu.: 190.0 1st Qu.: 1336 1st Qu.: 2.00
## Median : 4.00 Median : 697.5 Median : 2636 Median : 5.00
## Mean : 6.67 Mean :1050.8 Mean : 4224 Mean : 8.36
## 3rd Qu.: 8.25 3rd Qu.:1168.5 3rd Qu.: 4889 3rd Qu.:10.25
## Max. :44.00 Max. :8027.0 Max. :30757 Max. :57.00
##
## NWBIR79
## Min. : 3.0
## 1st Qu.: 250.5
## Median : 874.5
## Mean : 1352.8
## 3rd Qu.: 1406.8
## Max. :11631.0
##
```
```r
plot(sids)
```

### Maptools package
The `maptools` package has an alternative function for importing shapefiles that can be a little easier to use (but has fewer options).
* `readShapeSpatial`
```r
sids <- readShapeSpatial(file)
```
```
## Warning: use rgdal::readOGR or sf::st_read
## Warning: use rgdal::readOGR or sf::st_read
```
### Raster data
We'll deal with raster data in the next section.
# Coordinate Systems
* Earth isn't flat
* But small parts of it are close enough
* Many coordinate systems exist
* Anything `Spatial*` (or `raster*`) can have one
## Specifying the coordinate system
### The [Proj.4](https://trac.osgeo.org/proj/) library
Library for performing conversions between cartographic projections.
See [http://spatialreference.org](http://spatialreference.org) for information on specifying projections. For example,
#### Specifying coordinate systems
**WGS 84**:
* proj4: