5

I would like to ask some help for converting a shapefile to data frame. I downloaded data related to roads from Natural Earth. I imported the shapefile using shapefiles package like the following.

foo <- read.shp("ne_10m_roads_north_america.shp")

Then,I checked str(foo) and saw the following. This is just the beginning part.

> str(foo)
List of 2
 $ shp   :List of 49183
  ..$ :List of 8
  .. ..$ record        : int 1
  .. ..$ content.length: int 656
  .. ..$ shape.type    : int 3
  .. ..$ box           : Named num [1:4] -119.6 37.8 -119.6 37.9
  .. .. ..- attr(*, "names")= chr [1:4] "xmin" "ymin" "xmax" "ymax"
  .. ..$ num.parts     : int 1
  .. ..$ num.points    : int 79
  .. ..$ parts         : int 0
  .. ..$ points        :'data.frame':   79 obs. of  2 variables:
  .. .. ..$ X: num [1:79] -120 -120 -120 -120 -120 ...
  .. .. ..$ Y: num [1:79] 37.9 37.9 37.9 37.9 37.9 ...
  ..$ :List of 8
  .. ..$ record        : int 2
  .. ..$ content.length: int 40
  .. ..$ shape.type    : int 3
  .. ..$ box           : Named num [1:4] -119.8 39.1 -119.7 39.1
  .. .. ..- attr(*, "names")= chr [1:4] "xmin" "ymin" "xmax" "ymax"
  .. ..$ num.parts     : int 1
  .. ..$ num.points    : int 2
  .. ..$ parts         : int 0
  .. ..$ points        :'data.frame':   2 obs. of  2 variables:
  .. .. ..$ X: num [1:2] -120 -120
  .. .. ..$ Y: num [1:2] 39.1 39.1

I usually do something like this.

df <- data.frame(matrix(unlist(foo), nrow=100, byrow=T))

But, it seems that each list had different numbers of rows. So I am not sure if this approach is right. I have also tried the following. do.call(rbind) will be probably slow even if it works. rbindlist() indicates the numbers of columns different among items. tidyr got a nice new function called unnest() which would work, but R crashed.

> test<- do.call(rbind.data.frame, foo)

Error in data.frame(record = 1L, content.length = 656L, shape.type = 3L,  : 
  arguments imply differing number of rows: 1, 4, 79

> test <- rbindlist(foo)
Error in rbindlist(foo) : 
  Item 2 has 12 columns, inconsistent with item 1 which has 49183 columns

It seems to be a relatively easy thing to do, but I am not familiar with shapefiles. How can I approach this situation?

8

To read your shapefile, i recommend you to use rgdal package and its readOGR function, or eventually use readShapeLines from maptools package. These packages rely on the sp package as concerning how the geospatial data is structured in R.

You can do easily this to convert your shapefile into data.frame (ie extract the attributes of the shapefile)

require(rgdal)
foo <- readOGR(dsn=".",layer="ne_10m_roads_north_america")
foo.df <- as(foo, "data.frame")

And that's it!

Note: If we compare readOGR and readShapeLines in term of performance, readShapeLines seems to give better results:

-with readOGR

user  system elapsed
114.48    7.34  123.83

-with readShapeLines

user  system elapsed 
76.28    0.43   78.05
  • Nice and easy. Or simply execute foo.df <- foo@data. Same result! – fdetsch Sep 26 '14 at 8:43
  • exactly! you can accessing the data slot in this way, or doing slot(foo, "data"). as.data.frame is more a convenience method here useful for people who don't necessarily know about S4 and slots. – eblondel Sep 26 '14 at 8:50
  • All roads lead to Rome ;-) – fdetsch Sep 26 '14 at 8:52
  • @flowla @eblondel I see. I use readOGR to read files from GADM. I should have thought about the package. If you want to read shapelines, readShapeLines() is the safest? readOGR() good for polygon? and lines? – jazzurro Sep 26 '14 at 10:32
  • interesting point... i've now compared performance of readOGR vs. readShapeLines, and the latest gives faster results. – eblondel Sep 26 '14 at 10:43
2

Please read the sp vignette on spatial classes and methods.

vignette(package="sp")[4]
  vignette("intro_sp")

Since there is a slot (@data) that holds a data.frame related to the sp object, no coercion is required.

class(foo@data)
str(foo@data)
( df <- foo@data )

However, it is good practice to operate directly on the @data slot rather than pulling it to a new object. Not only is it more efficient it also avoids breaking the relationship between the row order and the slots in the sp object it relates to.

  • Thank you very much for your support. I will have a look of that. Cheers. – jazzurro Sep 26 '14 at 16:12
  • 1
    Note; I only use maptools shape read functions when I have broken topology. Otherwise, readOGR is a reliable generic method that can handle read/write of many vector formats all within the same function. It also retains projection information of the data. The same package, rgdal also handles raster formats. – Jeffrey Evans Sep 26 '14 at 18:11
1

You can use the Broom package.

Simply run:

my_df <- tidy(foo)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.