1

I have a nested list with multiple shapefiles and I want to use lapply with writeOGR ('rgdal') in order to export all the shapefiles. Sorry for not giving a reproducible example.

# My list 
shp.list
$e_ang
$e_ang$e_ang_g
class       : SpatialPolygonsDataFrame 
features    : 1291 
extent      : -1265736, 869263.7, -3051349, -1022949  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=eqdc +lat_0=0 +lon_0=25 +lat_1=20 +lat_2=-23 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       : e_ang_g 
min values  :       1 
max values  :       1 

$e_ang$e_ang_l
class       : SpatialPolygonsDataFrame 
features    : 1291 
extent      : -1265736, 869263.7, -3051349, -1022949  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=eqdc +lat_0=0 +lon_0=25 +lat_1=20 +lat_2=-23 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       : Value 
min values  :     1 
max values  :     1 

Here is the code I've used

# Using lapply to write shapefiles within list
lapply(unlist(shp.list), function(x) writeOGR(object = x,
                                         dsn = paste(fruit.bats, "output", sep = ''), # folder to store shapefiles 
                                         layer = names(x), # shapefile names as in shp.list
                                         driver = 'ESRI Shapefile',
                                         layer_options = 'RESIZE=YES',
                                         overwrite_layer = T))
# this returns 

$e_ang.e_ang_g
NULL

$e_ang.e_ang_l
NULL

I believe the problem is in the argument 'layer' in writeOGR. Probably I can create a vector to pass the names to the function, but I was wondering if there is a more direct way to do it. I would like the shapefiles to have the name of the nested elements, 'e_ang_g' and 'e_ang_l' in the example.


I was able to do the same with a loop, but still seek a solution using lapply.

Here is the code for the loop.

n <- substring(names(unlist(shp.list)), 7,13) # vector with shapefile names

for (j in 1:length(n)){
  writeOGR(unlist(shp.list)[[j]], 
           dsn = paste(fruit.bats, "output", sep = '/'),
           layer = n[j],
           driver = 'ESRI Shapefile',
           layer_options = 'RESIZE=YES',
           overwrite_layer = T) }
2
  • Why use lapply? The apply family is a very R way of performing recursive task and, in many cases, can speed things up considerable. However, in this instance there should be no difference in speed because the bottleneck will be writeOGR. The code for a for loop is about the same length so, it is not even about code efficiency. May 23, 2018 at 14:26
  • You can make a reproducible example with pts=data.frame(x=1:4,y=1:4);coordinates(pts)=~x+y;shp.list = list(e_ang = list(e_ang_g=pts,e_ang_l=pts), z_foo=list(a_foo=pts,b_foo=pts))
    – Spacedman
    May 23, 2018 at 14:38

1 Answer 1

3

This seems to replicate your list structure, which appears to be a list of lists of spatial data. I'll just put some character data in place of the spatial data:

shp.list = list(
   e_ang = list(
     e_ang_g="ggg",
     e_ang_l="lll"),
   z_foo=list(
     a_foo="aaa",
     b_foo="bbb"))

To loop over a list of lists you need a nested lapply:

> tmp = lapply(shp.list, function(e){lapply(e,function(s){message(s)})})
ggg
lll
aaa
bbb

the outer lapply is over the top-level elements, and the inner lapply goes over the elements of each top-level element.

What you probably want to do is loop over the names of the elements within each top-level element, and use those names to construct the shapefile name. I recommend using raster::shapefile since it works out the layer name for you from the file name. So this should work:

library(raster)
tmp = lapply(shp.list, function(L){
          lapply(names(L),function(n){
             shapefile(L[[n]],file=paste0(n,".shp"))
              })
          })

seems to have created things:

> list.files(pattern=".*shp")
[1] "a_foo.shp"   "b_foo.shp"   "e_ang_g.shp" "e_ang_l.shp"
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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