4

Here is the data for reproducible purposes:

  structure(list(countyfp10 = c(1, 1, 1, 1, 3, 3, 3, 3, 5, 5, 5, 
5, 7, 7, 7, 7), id = c(7417, 7418, 7419, 7420, 7421, 7422, 7423, 
7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432), lat = c(39.4797245, 
39.5544678, 39.4681687, 39.199806, 39.4017623, 39.3093943, 39.4272021, 
39.5618129, 39.7934997, 39.4835134, 39.4989196, 39.4819145, 39.4727694, 
39.4675515, 39.4693146, 39.4644503), long = c(-118.7908571, -118.8095638, 
-118.8195712, -118.5429041, -118.754186, -118.8861865, -118.9729817, 
-117.9418517, -118.9516281, -118.8487913, -119.0205114, -118.7695846, 
-118.7938896, -118.76011, -118.7778707, -118.7902103)), class = c("spec_tbl_df", 
"tbl_df", "tbl", "data.frame"), row.names = c(NA, -16L), spec = structure(list(
    cols = list(countyfp10 = structure(list(), class = c("collector_double", 
    "collector")), id = structure(list(), class = c("collector_double", 
    "collector")), lat = structure(list(), class = c("collector_double", 
    "collector")), long = structure(list(), class = c("collector_double", 
    "collector"))), default = structure(list(), class = c("collector_guess", 
    "collector")), skip = 1), class = "col_spec"))

This is currently store as a data.frame but I would like to convert it into a SpatialPolygonsDataFrame. What would be the best way to do it?

  • Does it have to be a `SpatialPolygonsDataFrame`, or can it be a simple feature object (`sf`), which is the successor to `sp`? – SymbolixAU Sep 03 '19 at 00:51
  • And, rather than putting a 'print' of your data, it's better to use the output of `dput(df)`. This way we can all simply copy & paste your data. – SymbolixAU Sep 03 '19 at 00:52
  • @SymbolixAU Thanks, just edited it. And I guess it doesn't need to be SpatialPolygonsDataFrame, if `sf` accomplishes the same thing? As long as it can be read by the `leaflet()` function –  Sep 03 '19 at 01:16

2 Answers2

4

I've developed the sfheaders library for this purpose.

devtools::install_github("dcooley/sfheaders")
library(sfheaders)

sf <- sfheaders::sf_polygon(
    obj = df
    , x = "long"
    , y = "lat"
    , polygon_id = "countyfp10"
)

And to show it works in leaflet (other plotting libraries are available ;) )

library(leaflet)
leaflet() %>%
    addTiles() %>%
    addPolygons(data = sf)

enter image description here

SymbolixAU
  • 25,502
  • 4
  • 67
  • 139
  • Thanks, but I keep getting this error message: ```Downloading GitHub repo dcooley/sfheaders@master Error: Failed to install 'sfheaders' from GitHub: Could not find tools necessary to compile a package Call `pkgbuild::check_build_tools(debug = TRUE)` to diagnose the problem.``` –  Sep 03 '19 at 01:41
  • weird... have you run `pkgbuild::check_build_tools(debug = TRUE)` ? – SymbolixAU Sep 03 '19 at 01:42
  • It takes me to this page: https://www.cnet.com/how-to/install-command-line-developer-tools-in-os-x/ –  Sep 03 '19 at 01:43
  • Do you have the CRAN version of `devtools`? – SymbolixAU Sep 03 '19 at 01:46
  • The coordinates in the dataset dont form a closed polygon. Do you force close them in the package? – Sada93 Sep 03 '19 at 01:48
  • @gooponyagrinch This is slightly beyond my knowledge I'm afraid. [This thread](https://github.com/r-lib/devtools/issues/1879#issuecomment-426426380) looks like it's part of the issue – SymbolixAU Sep 03 '19 at 01:49
  • @Sada93 no I don't force anything; I assume the data is correct and use it as-is. – SymbolixAU Sep 03 '19 at 01:50
  • doesn't sf throw an error if the polygons are not closed? ie: coordinates of the first row and last row in each group are not the same. – Sada93 Sep 03 '19 at 01:51
  • @sada93 that's not surprising. I just did a random sample of 10. –  Sep 03 '19 at 01:51
  • @SymbolixAU since I can't get your package working, is there an alternative that doesn't involve it? –  Sep 03 '19 at 01:59
  • @SymbolixAU wait I think I got the package working! –  Sep 03 '19 at 02:08
  • 1
    @Sada93 yes it will error if you try to construct it using the `sf::st_polygon()` constructor. BUT, there are ways around it `geo <- '{"type":"Polygon","coordinates":[[[0,0],[1,1]]]}'; res <- sf::st_read( geo )` , which gives you a valid `sf` object – SymbolixAU Sep 03 '19 at 02:29
  • 1
    @Sada93 I've taken your comment on board and for the next release I'm forcing polygons to be closed by default, but you can override this too - https://github.com/dcooley/sfheaders/issues/34 – SymbolixAU Sep 24 '19 at 22:41
1

As mentioned in the comments, sf is the most convenient package to use, here is an example.

Note the data set was modified to form a closed polygon, if we try it with the original data, it throws an error.

data = tibble(countyfp10 = c(1, 1, 1, 1,1, 3, 3, 3, 3,3, 5, 5, 5,5,
                              5, 7, 7, 7, 7,7), id = c(7413,7414,7415,7416,7417, 7418, 7419, 7420, 7421, 7422, 7423, 
                                                     7424, 7425, 7426, 7427, 7428, 7429, 7430, 7431, 7432), lat = c(39.4797245, 
                                                                                                                    39.5544678, 39.4681687, 39.199806,39.4797245, 39.4017623, 39.3093943, 39.4272021, 
                                                                                                                    39.5618129,39.4017623, 39.7934997, 39.4835134, 39.4989196, 39.4819145,39.7934997, 39.4727694, 
                                                                                                                    39.4675515, 39.4693146, 39.4644503,39.4727694), lng = c(-118.7908571, -118.8095638, 
                                                                                                                                                                  -118.8195712, -118.5429041,-118.7908571, -118.754186, -118.8861865, -118.9729817, 
                                                                                                                                                                  -117.9418517,-118.754186, -118.9516281, -118.8487913, -119.0205114, -118.7695846,-118.9516281, 
                                                                                                                                                                  -118.7938896, -118.76011, -118.7778707, -118.7902103,-118.7938896))

cords = data%>%
  select(countyfp10,lng,lat)%>%
  mutate(lng = as.numeric(lng),
         lat = as.numeric(lat))%>%
  group_by(countyfp10)%>%
  summarise(coordinates = list(list(matrix(c(lng,lat),ncol = 2)))) %>%
  .$coordinates %>%
  lapply(.,st_polygon) %>%
  st_sfc(.)

cords %>% 
  leaflet() %>%
  addTiles()%>%
  addPolygons()
UseR10085
  • 7,120
  • 3
  • 24
  • 54
Sada93
  • 2,785
  • 1
  • 10
  • 21