1

Thanks for taking a look at my question.

I'm having some trouble with a nested for loop in R. The data I'm trying to loop through is a list of spatial lines items - sfc_linestring. There are 142 linestrings in total. I would like to rotate each linestring element 1000 times about it's centroid. Therefore I have an outer loop designed to loop over the 142 linestring elements and an inner loop designed to rotate each linestring element 1000 times. My code looks like this:

    library(tidyverse)
    library(sf)
    library(sfheaders)
    
    vlines_rotate<- st_sfc(st_linestring(matrix(c(0,0), 1000,2)),
                             st_linestring(matrix(c(0,0), 1000,2)))
    theta=runif(n=142000, min=1, max=359)

    for(i in seq_along(vlines_sfc)){
    for(j in seq_along(theta)){
    vlines_rotate[j]=(vlines_sfc[i]- 
    vlines_centroid[i])*rot(theta[j])+vlines_centroid[i]
   }
   }

where "vlines_sfc" is my 142 element linestring object, "vlines_centroid" is a list of 142 elements of sfc_point data corresponding to the centroid of each of the 142 linestring elements in "vlines_sfc", "theta" is a vector of values for the rotation of length 142,000 and "rot" is a predefined function to execute the rotation:

    rot = function(a) matrix(c(cos(a), sin(a), -sin(a), cos(a)), 2, 2)

When I run that code as is, it only loops over the first element of the "vline_sfc" list.

Here are three elements of the "vlines_sfc" list to help provide a reproducible example:

first:

         structure(c(-8.04785755607144, -8.04785755455143, 
         -8.04791145480662, 
         -8.04819648729046, 52.6437603276574, 52.643758935097, 
         52.6435415730872, 
 52.6436586891848), .Dim = c(4L, 2L), .Dimnames = list(NULL, c("x", 
 "y")), class = c("XY", "LINESTRING", "sfg"))

second:

    structure(c(-9.59085243559515, -9.59113171718261, 
  -9.59142986404616, -9.59178373602288, -9.59223453048505, 
 -9.59244593714847, -9.59275643486916, -9.59282667794028, 
  52.3098294867051, 52.3099104253679, 52.3099669079775, 
 52.309925838634, 52.3098350614709, 52.3096749090167, 
 52.3095255206016, 52.3092825718973), .Dim = c(8L, 2L), .Dimnames = 
  list(NULL, c("x", "y")), class = c("XY", "LINESTRING", "sfg"))

and third:

  structure(c(-8.04123430428425, -8.04208275315675, -8.04302533321555, 
 -8.0443453420333, -8.0451940859463, -8.04657772707061, 
 -8.04811912935648, -8.04887424957855, 52.6418076510363, 
  52.6413674859761, 52.6407551588562, 52.6403339300028, 
  52.6402379861024, 52.6405625693178, 52.6413843131718, 
  52.6419003695025), .Dim = c(8L, 2L), .Dimnames = list(NULL, c("x", 
  "y")), class = c("XY", "LINESTRING", "sfg"))

And here are the corresponding centroid points, from the "vlines_centroid" list, for each of the above linestring elements:

first:

    structure(c(-8.04798232118289, 52.6436215876677), class = c("XY", 
    "POINT", "sfg"))      

second:

    structure(c(-9.59193417120938, 52.309787085248), class = c("XY", 
   "POINT", "sfg"))

third:

   structure(c(-8.04507115847921, 52.6408903075153), class = c("XY", 
  "POINT", "sfg"))

I have tried executing the loops individually and they work as expected; i.e. when running the outer loop alone with a basic function like "print" inside, it runs as you might expect. Similarly, when I run the inner loop and call individual elements of "vlines_sfc" object, i.e. substituting [i] for [1] or [2] etc, and reducing "theta" to 1000, this works perfectly. I therefore suspect this has something to do with how I've nested the loops(?). Other things I have tried include substituting "seq_along()" for "1:length()" in the outer loop but I get an identical result. I have also tried using double brackets around [[i]] to ensure the loop recognises that "vlines_sfc" and "vlines_centroid" are lists but to no success.

This is the first time I have attempted to nest for loops so would really appreciate any advice. I realise that for loops are not looked upon as 'good code' and I would appreciate an answer where I can achieve what I need through vectorisation but unfortunately I find for loops easier to understand and execute, so if you might have a way to vectorise this then please, if you can, could you also explain or help me understand how to go about it too.

Hopefully I have provided enough detail but please comment if not (I'm new to Stack Overflow). Thank you to the user that did comment and prompted me for more detail.

Many Thanks

Nicola
  • 11
  • 2
  • Welcome to SO! Please have a look how to provide a [minimal reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example), in your case provide all packages needed and make a small data example. Then it's easier to help you, thanks! – starja Jun 01 '21 at 11:46
  • 1
    Thank you for pointing this out. I've now updated my question with more detail which will hopefully help clarify what I'm asking. Please let me know if not. – Nicola Jun 01 '21 at 15:53
  • Can you simplify your exmaple by giving us an example of `vlines_sfc` - it only has to have 2 LINESTRINGS inside it, and they only have to have a couple of POINTs in each linestring. – SymbolixAU Jun 01 '21 at 23:04
  • Hi @SymbolixAU, thanks for having a look at my question. I have provided three linestring elements from vlines_sfc in the question - the third, fourth and fifth blocks of code in the text above, followed by the points from the vlines_centroid list. I think this is what you're asking, but please let me know if not. – Nicola Jun 02 '21 at 10:29

0 Answers0