Create SpatialPointsDataframe

38,004

Solution 1

It uses the row order to ensure the match between coordinates and the data. And, you can tell it what columns to use for lon/lat. Here's a few examples that hopefully make it a bit clearer:

library(sp)

dat_orig <- read.table(text="    a    b    c    d    e    lat   lng
 12   f2   23   dd   2d   15.6  80.9
 12   g5   99   NA   hh   20.9  10.9
 13   g4   12   aa   3r3  1.2   81.8", header=TRUE, stringsAsFactors=FALSE)

dat <- dat_orig
coordinates(dat) <- ~lng+lat

dat
##    coordinates  a  b  c    d   e
## 1 (80.9, 15.6) 12 f2 23   dd  2d
## 2 (10.9, 20.9) 12 g5 99 <NA>  hh
## 3  (81.8, 1.2) 13 g4 12   aa 3r3


dat_1 <- dat_orig
colnames(dat_1) <- c(colnames(dat_1)[1:5], "steve", "larry")
coordinates(dat_1) <- ~larry+steve

dat_1
##    coordinates  a  b  c    d   e
## 1 (80.9, 15.6) 12 f2 23   dd  2d
## 2 (10.9, 20.9) 12 g5 99 <NA>  hh
## 3  (81.8, 1.2) 13 g4 12   aa 3r3


dat_2 <- SpatialPointsDataFrame(dat_orig[,c("lng", "lat")], dat_orig[,1:5])
dat_2
##    coordinates  a  b  c    d   e
## 1 (80.9, 15.6) 12 f2 23   dd  2d
## 2 (10.9, 20.9) 12 g5 99 <NA>  hh
## 3  (81.8, 1.2) 13 g4 12   aa 3r3


dat_3 <- dat_orig
colnames(dat_3) <- c(colnames(dat_3)[1:5], "steve", "larry")
dat_3 <- SpatialPointsDataFrame(dat_3[,c("larry", "steve")], dat_3[,1:5])

dat_3
##    coordinates  a  b  c    d   e
## 1 (80.9, 15.6) 12 f2 23   dd  2d
## 2 (10.9, 20.9) 12 g5 99 <NA>  hh
## 3  (81.8, 1.2) 13 g4 12   aa 3r3

And, here's what coordinates<- is doing under the covers:

setReplaceMethod("coordinates", signature(object = "data.frame", value = "ANY"),
  function(object, value) {
  coord.numbers = NULL
  if (inherits(value, "formula")) {
    cc = model.frame(value, object, na.action = na.fail) # retrieve coords
    if (dim(cc)[2] == 2) {
      nm = as.character(as.list(value)[[2]])[2:3]
      coord.numbers = match(nm, names(object))
    } else if (dim(cc)[2] == 3) {
      nm = c(as.character(as.list((as.list(value)[[2]])[2])[[1]])[2:3],
        as.character(as.list(value)[[2]])[3])
      coord.numbers = match(nm, names(object))
    } # else: give up.
  } else if (is.character(value)) {
    cc = object[, value] # retrieve coords
    coord.numbers = match(value, names(object))
  } else if (is.null(dim(value)) && length(value) > 1) { # coord.columns?
    if (any(value != as.integer(value) || any(value < 1)))
      stop("coordinate columns should be positive integers")
    cc = object[, value] # retrieve coords
    coord.numbers = value
  } else  # raw coordinates given; try transform them to matrix:
    cc = coordinates(value)
  if (any(is.na(cc)))
    stop("coordinates are not allowed to contain missing values")
  if (!is.null(coord.numbers)) {
    object = object[ , -coord.numbers, drop = FALSE]
    stripped = coord.numbers
    # ... but as.data.frame(x) will merge them back in, so nothing gets lost.
    if (ncol(object) == 0)
      #stop("only coords columns present: use SpatialPoints to create a points object")
      return(SpatialPoints(cc))
  } else
    stripped = numeric(0)
  SpatialPointsDataFrame(coords = cc, data = object, coords.nrs = stripped,
    match.ID = FALSE)
  }
)

Which shows it's just doing the SpatialPointsDataFrame idiom for you in a shorter call.

Solution 2

To make a SpatialPointsDataFrame you need 3 components:

  1. coordinates
  2. data
  3. proj4string of the coordinates (AKA, coordinate reference system (CRS))

# load some example data
library(sp)                       # spatial library
data(meuse)                       # load built in dataset

# prepare coordinates, data, and proj4string
coords <- meuse[ , c("x", "y")]   # coordinates
data   <- meuse[ , 3:14]          # data
crs    <- CRS("+init=epsg:28992") # proj4string of coords

# make the SpatialPointsDataFrame object
spdf <- SpatialPointsDataFrame(coords      = coords,
                               data        = data, 
                               proj4string = crs)

# check the object class
class(spdf)

[1] "SpatialPointsDataFrame"
attr(,"package")
[1] "sp"

# plot the copper column 
spplot(spdf, "copper")

enter image description here

Share:
38,004

Related videos on Youtube

four-eyes
Author by

four-eyes

Updated on June 10, 2020

Comments

  • four-eyes
    four-eyes almost 4 years

    I have a dataframe df1 with 10 columns. Two of these columns are lng and lat. I want to create a SpatialPointsDataframe from df1. When I read on how to create a SpatialPointsDataframe it feels like I have to create a matrix m1 from my two coordinates columns and then assign that matrix to the dataframe ´df1`.

    That would be a detour since my coordinates are already a column in my dataframe df1. Furthermore, how do I assure that the coordinates from my matrix m1 are assign to the correct rows in my dataframe df1?

    thats how my df1 would look like

    > df1
        a    b    c    d    e    lat   lng
    1   12   f2   23   dd   2d   15.6  80.9
    2   12   g5   99   NA   hh   20.9  10.9
    3   13   g4   12   aa   3r3  1.2   81.8
    4   ..   ..   ..   ..   ..   ..    .. 
    
    • hrbrmstr
      hrbrmstr over 8 years
      dput(df1) wld be helpful
    • four-eyes
      four-eyes over 8 years
      @hrbrmstr what would you need that for? I am asking a question related to the process of the creation of a spatial data frame.
    • rcs
      rcs over 8 years
      @Chrissl Just use coordinates(df1) <- ~ lng + lat; this casts the data frame to an SpatialPointsDataFrame
    • four-eyes
      four-eyes over 8 years
      @rcs thats exactly what I wonder. Where do I define lng + lat?! Do I need to extract them from df1 like lng <- df1$lng and lat <- df1$lat. If so, how does coordinates know which coordinates assign to which row. Does it do that by order, by a key? Or do I need to do something like coordinates(df1) <- ~ df1$lng + df1$lat
    • hrbrmstr
      hrbrmstr over 8 years
      @Chrissl your "wonder" is exactly why having data to show a minimal example would be helpful vs an extended discussion in the comments or asking others to make data up to show you.
  • four-eyes
    four-eyes over 8 years
    Sweet. Thanks. I did not know that it does all of that automatically. I thought I need to tell it somewhere more on "how to match".