I have a shapefile (sf) object made up of polygons with polygon characteristics stored in a dataframe. This object is called tiles. Within the dataframe there are 12 variables indicating number of pixels that transitioned to zero forest cover by year called loss2001, loss 2002, ... loss2012. Each variable is indexed by a unique identifier ID.

tiles = st_read("ShapefileForestlossGroup1")

I want to reshape this shapefile dataframe so that I can produce annual spatial weights. The problem is that many reshaping options are best executed with a data table, but if I transform tiles into a data table, it is no longer an sf object.

As an sf object with a dataframe, I tried executing the following reshape function:

tiles2 = reshape(tiles, 
        direction = "long",
        varying = list(names(tiles)[1:12]),
        v.names = "numPixelsDeforested",
        idvar = "ID",
        timevar = "Year",
        times = 2001:2012)

But R returns the following error:

Error in `.rowNamesDF<-`(x, value = value) : invalid 'row.names' length In addition: Warning message: In `[<-.data.frame`(`*tmp*`, , v.names, value = list(loss2001 = c(0L, : provided 2 variables to replace 1 variables

Could these errors be related to the fact that this is an sf object dataframe, or is the syntax just wrong?

  • I don't get an error if I generate a thing like this with three columns and a geometry: tiles = st_as_sf(data.frame(x=runif(10),y=runif(10), loss2001=runif(10), loss2002=runif(10), loss2003=runif(10)), coords=1:2) - do you? I get the warnings but the resultant object looks okay. – Spacedman Dec 4 '20 at 17:41
  • I don't get warnings if I turn the spatial data frame into a non-spatial frame by dropping the geometry and using your reshape code. In a pinch you could do that and then add a geometry column that is N copies of the source geometry (where N=12 for you). – Spacedman Dec 4 '20 at 17:42
  • When I execute this function, tiles_2 does not generate. And I am open to transforming into a non-spatial frame and transforming back when it is done, but I am worried that transferring back to an sf object will be very complicated. – C. Ashley Dec 4 '20 at 18:20
  • Spacedman - I was able to execute the function on the tiles data you generated. But I notice that the spatial objects of this fake data is points. I have polygons. – C. Ashley Dec 4 '20 at 18:37
  • Does it only fail if its polygons? That's an interesting discovery that we can now look into... – Spacedman Dec 4 '20 at 22:32

With the help of the comments above I think we were able to scrape together a solution.

If you redefine your sf object as a data.frame, and then reshape:

tilesDF = as.data.frame(tilesNoNA)

tilesReshape= reshape(tilesDF, 
        direction = "long",
        varying = list(names(tilesDF)[1:12]),
        v.names = "numPixelsDeforested",
        idvar = "ID",
        timevar = "Year",
        times = 2001:2012)

You can then transform this long dataframe back into an sf object using:

tilesLong = st_as_sf(tilesReshape, sf_column_name = 'geometry')

The option sf_column_name in st_as_sf is really, really handy.

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.