help: Problem getting centroids inside lists

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

help: Problem getting centroids inside lists

aestfd
Hi everyone,

I have a list of coordinates called "ct" and I want to extract the
centroids of each sublist, but it only works when it has only 3 or more
points. In ct$b$two only has one point; in that case, I would rescue that
point as If it were a centroid.

This is what I did:

library(dplyr)
library(geosphere)

ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat = c(-20,
5, 0)),
                    two = data.frame(lon = c(-18, -16, -6), lat = c(-2, 50,
10))),
           b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1, 25,
5)),
                    two = data.frame(lon = c(-90), lat = c(-1))))

coordinates(ct$a$one) <- ~lon+lat
coordinates(ct$a$two) <- ~lon+lat
coordinates(ct$b$one) <- ~lon+lat
coordinates(ct$b$two) <- ~lon+lat

s <- 1:length(ct)
ctply <- list()
for (i in s){
 for (j in 1:length(ct[[i]])) {
  ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes = sapply(X =
ct[[i]][j],
    FUN = function(y) geosphere::centroid(slot(y, "coords"))), no =
ct[[i]][j] )
 }
}

Thanks in advance

Regards,
Ariel

        [[alternative HTML version deleted]]

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo
Reply | Threaded
Open this post in threaded view
|

Re: help: Problem getting centroids inside lists

R-sig-geo mailing list
If all of your data frames had enough points then this should work:

myfun1 <- function(le) {
  list(one=geosphere::centroid(coordinates(le$one)),
       two=geosphere::centroid(coordinates(le$two))
       )
}

lapply(ct, myfun1)

To handle the one point case, try the following, which I think works with your example data, but is untested if there just two points.
It also assumes the data frames are named 'one' and 'two', and will ignore any others. To handle other names, I think you
could replace  $one  with  [[1]]  and  $two  with  [[2]]  .

myfun <- function(le) {
  list(one=if (length(le$one)>1) geosphere::centroid(coordinates(le$one)) else coodinates(le$one),
       two=if (length(le$two)>1) geosphere::centroid(coordinates(le$two)) else coordinates(le$two)
       )
}

lapply(ct, myfun)


To see a little bit of what's going on, try

  myfun(ct[[1]])
  myfun1(ct[[1]])
  myfun1(ct[[2]])
  myfun(ct[[2]])



I would also verify that the length method for objects of class SpatialPoints does return the number of points, as it appears to:

> class(ct$a$two)
[1] "SpatialPoints"
attr(,"package")
[1] "sp"

> length(ct$a$one)
[1] 3
> length(ct$a$two)
[1] 3
> length(ct$a$two)
[1] 3
> length(ct$b$two)
[1] 1

--
Don MacQueen
Lawrence Livermore National Laboratory
7000 East Ave., L-627
Livermore, CA 94550
925-423-1062
Lab cell 925-724-7509
 
 

On 9/10/18, 10:56 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <[hidden email] on behalf of [hidden email]> wrote:

    Hi everyone,
   
    I have a list of coordinates called "ct" and I want to extract the
    centroids of each sublist, but it only works when it has only 3 or more
    points. In ct$b$two only has one point; in that case, I would rescue that
    point as If it were a centroid.
   
    This is what I did:
   
    library(dplyr)
    library(geosphere)
   
    ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat = c(-20,
    5, 0)),
                        two = data.frame(lon = c(-18, -16, -6), lat = c(-2, 50,
    10))),
               b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1, 25,
    5)),
                        two = data.frame(lon = c(-90), lat = c(-1))))
   
    coordinates(ct$a$one) <- ~lon+lat
    coordinates(ct$a$two) <- ~lon+lat
    coordinates(ct$b$one) <- ~lon+lat
    coordinates(ct$b$two) <- ~lon+lat
   
    s <- 1:length(ct)
    ctply <- list()
    for (i in s){
     for (j in 1:length(ct[[i]])) {
      ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes = sapply(X =
    ct[[i]][j],
        FUN = function(y) geosphere::centroid(slot(y, "coords"))), no =
    ct[[i]][j] )
     }
    }
   
    Thanks in advance
   
    Regards,
    Ariel
   
    [[alternative HTML version deleted]]
   
    _______________________________________________
    R-sig-Geo mailing list
    [hidden email]
    https://stat.ethz.ch/mailman/listinfo/r-sig-geo
   

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo
Reply | Threaded
Open this post in threaded view
|

Re: help: Problem getting centroids inside lists

aestfd
I went to a more general approach, that is:

ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
          FUN = function(y) if(length(y)>1) geosphere::centroid(slot(y,
"coords"))
          else sp::coordinates(slot(y, "coords"))))

But now I want to add the case when they are only two elements. The dataset
will be:

ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat = c(-20,
5, 0)),
                    two = data.frame(lon = c(-18, -16), lat = c(-2, 50))),
           b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1, 25,
5)),
                    two = data.frame(lon = c(-90), lat = c(-1))))
coordinates(ct$a$one) <- ~lon+lat
coordinates(ct$a$two) <- ~lon+lat
coordinates(ct$b$one) <- ~lon+lat
coordinates(ct$b$two) <- ~lon+lat

And I did the following but it doesn't work:

ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
                                                FUN = function(y)
if(length(y)>2) geosphere::centroid(slot(y, "coords"))
                                                else if (length(y) == 1)
sp::coordinates(slot(y, "coords"))
                                                else
mean(sp::coordinates(slot(y, "coords")))))

I need the result of each element of the list will be a matrix of two rows
per column (named: one, two). How do I fix it?

Regards,
Ariel

2018-09-10 17:29 GMT-03:00 MacQueen, Don <[hidden email]>:

> If all of your data frames had enough points then this should work:
>
> myfun1 <- function(le) {
>   list(one=geosphere::centroid(coordinates(le$one)),
>        two=geosphere::centroid(coordinates(le$two))
>        )
> }
>
> lapply(ct, myfun1)
>
> To handle the one point case, try the following, which I think works with
> your example data, but is untested if there just two points.
> It also assumes the data frames are named 'one' and 'two', and will ignore
> any others. To handle other names, I think you
> could replace  $one  with  [[1]]  and  $two  with  [[2]]  .
>
> myfun <- function(le) {
>   list(one=if (length(le$one)>1) geosphere::centroid(coordinates(le$one))
> else coodinates(le$one),
>        two=if (length(le$two)>1) geosphere::centroid(coordinates(le$two))
> else coordinates(le$two)
>        )
> }
>
> lapply(ct, myfun)
>
>
> To see a little bit of what's going on, try
>
>   myfun(ct[[1]])
>   myfun1(ct[[1]])
>   myfun1(ct[[2]])
>   myfun(ct[[2]])
>
>
>
> I would also verify that the length method for objects of class
> SpatialPoints does return the number of points, as it appears to:
>
> > class(ct$a$two)
> [1] "SpatialPoints"
> attr(,"package")
> [1] "sp"
>
> > length(ct$a$one)
> [1] 3
> > length(ct$a$two)
> [1] 3
> > length(ct$a$two)
> [1] 3
> > length(ct$b$two)
> [1] 1
>
> --
> Don MacQueen
> Lawrence Livermore National Laboratory
> 7000 East Ave., L-627
> Livermore, CA 94550
> 925-423-1062
> Lab cell 925-724-7509
>
>
>
> On 9/10/18, 10:56 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <
> [hidden email] on behalf of [hidden email]>
> wrote:
>
>     Hi everyone,
>
>     I have a list of coordinates called "ct" and I want to extract the
>     centroids of each sublist, but it only works when it has only 3 or more
>     points. In ct$b$two only has one point; in that case, I would rescue
> that
>     point as If it were a centroid.
>
>     This is what I did:
>
>     library(dplyr)
>     library(geosphere)
>
>     ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat =
> c(-20,
>     5, 0)),
>                         two = data.frame(lon = c(-18, -16, -6), lat =
> c(-2, 50,
>     10))),
>                b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1,
> 25,
>     5)),
>                         two = data.frame(lon = c(-90), lat = c(-1))))
>
>     coordinates(ct$a$one) <- ~lon+lat
>     coordinates(ct$a$two) <- ~lon+lat
>     coordinates(ct$b$one) <- ~lon+lat
>     coordinates(ct$b$two) <- ~lon+lat
>
>     s <- 1:length(ct)
>     ctply <- list()
>     for (i in s){
>      for (j in 1:length(ct[[i]])) {
>       ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes =
> sapply(X =
>     ct[[i]][j],
>         FUN = function(y) geosphere::centroid(slot(y, "coords"))), no =
>     ct[[i]][j] )
>      }
>     }
>
>     Thanks in advance
>
>     Regards,
>     Ariel
>
>         [[alternative HTML version deleted]]
>
>     _______________________________________________
>     R-sig-Geo mailing list
>     [hidden email]
>     https://stat.ethz.ch/mailman/listinfo/r-sig-geo
>
>
>

        [[alternative HTML version deleted]]

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo
Reply | Threaded
Open this post in threaded view
|

Re: help: Problem getting centroids inside lists

Vijay Lulla
Maybe the following function is what you're looking for?

getcentroids <- function(x1) {
  getcentroid <- function(x) {
    coords <- slot(x, "coords")
    numrows <- dim(coords)[1]
    ret <- if(numrows == 2) {
      matrix(apply(coords,2,mean), nrow=1)
    } else {
      if(numrows == 1) {
        coords
      } else {
        geosphere::centroid(coords)
      }
    }
    ret
  }

  r <- lapply(x1, function(x) as.data.frame(getcentroid(x)))

  ret <- matrix(unlist(r), ncol=2, byrow=TRUE)
  rownames(ret) <- names(r); colnames(ret) <- c("lon", "lat")

  ret
}

Now call it as lapply(ct, getcentroids)

HTH,
Vijay.

On Wed, Sep 12, 2018 at 2:42 PM Ariel Fuentesdi <[hidden email]>
wrote:

> I went to a more general approach, that is:
>
> ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
>           FUN = function(y) if(length(y)>1) geosphere::centroid(slot(y,
> "coords"))
>           else sp::coordinates(slot(y, "coords"))))
>
> But now I want to add the case when they are only two elements. The dataset
> will be:
>
> ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat = c(-20,
> 5, 0)),
>                     two = data.frame(lon = c(-18, -16), lat = c(-2, 50))),
>            b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1, 25,
> 5)),
>                     two = data.frame(lon = c(-90), lat = c(-1))))
> coordinates(ct$a$one) <- ~lon+lat
> coordinates(ct$a$two) <- ~lon+lat
> coordinates(ct$b$one) <- ~lon+lat
> coordinates(ct$b$two) <- ~lon+lat
>
> And I did the following but it doesn't work:
>
> ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
>                                                 FUN = function(y)
> if(length(y)>2) geosphere::centroid(slot(y, "coords"))
>                                                 else if (length(y) == 1)
> sp::coordinates(slot(y, "coords"))
>                                                 else
> mean(sp::coordinates(slot(y, "coords")))))
>
> I need the result of each element of the list will be a matrix of two rows
> per column (named: one, two). How do I fix it?
>
> Regards,
> Ariel
>
> 2018-09-10 17:29 GMT-03:00 MacQueen, Don <[hidden email]>:
>
> > If all of your data frames had enough points then this should work:
> >
> > myfun1 <- function(le) {
> >   list(one=geosphere::centroid(coordinates(le$one)),
> >        two=geosphere::centroid(coordinates(le$two))
> >        )
> > }
> >
> > lapply(ct, myfun1)
> >
> > To handle the one point case, try the following, which I think works with
> > your example data, but is untested if there just two points.
> > It also assumes the data frames are named 'one' and 'two', and will
> ignore
> > any others. To handle other names, I think you
> > could replace  $one  with  [[1]]  and  $two  with  [[2]]  .
> >
> > myfun <- function(le) {
> >   list(one=if (length(le$one)>1) geosphere::centroid(coordinates(le$one))
> > else coodinates(le$one),
> >        two=if (length(le$two)>1) geosphere::centroid(coordinates(le$two))
> > else coordinates(le$two)
> >        )
> > }
> >
> > lapply(ct, myfun)
> >
> >
> > To see a little bit of what's going on, try
> >
> >   myfun(ct[[1]])
> >   myfun1(ct[[1]])
> >   myfun1(ct[[2]])
> >   myfun(ct[[2]])
> >
> >
> >
> > I would also verify that the length method for objects of class
> > SpatialPoints does return the number of points, as it appears to:
> >
> > > class(ct$a$two)
> > [1] "SpatialPoints"
> > attr(,"package")
> > [1] "sp"
> >
> > > length(ct$a$one)
> > [1] 3
> > > length(ct$a$two)
> > [1] 3
> > > length(ct$a$two)
> > [1] 3
> > > length(ct$b$two)
> > [1] 1
> >
> > --
> > Don MacQueen
> > Lawrence Livermore National Laboratory
> > 7000 East Ave., L-627
> > Livermore, CA 94550
> > 925-423-1062
> > Lab cell 925-724-7509
> >
> >
> >
> > On 9/10/18, 10:56 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <
> > [hidden email] on behalf of [hidden email]>
> > wrote:
> >
> >     Hi everyone,
> >
> >     I have a list of coordinates called "ct" and I want to extract the
> >     centroids of each sublist, but it only works when it has only 3 or
> more
> >     points. In ct$b$two only has one point; in that case, I would rescue
> > that
> >     point as If it were a centroid.
> >
> >     This is what I did:
> >
> >     library(dplyr)
> >     library(geosphere)
> >
> >     ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat =
> > c(-20,
> >     5, 0)),
> >                         two = data.frame(lon = c(-18, -16, -6), lat =
> > c(-2, 50,
> >     10))),
> >                b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1,
> > 25,
> >     5)),
> >                         two = data.frame(lon = c(-90), lat = c(-1))))
> >
> >     coordinates(ct$a$one) <- ~lon+lat
> >     coordinates(ct$a$two) <- ~lon+lat
> >     coordinates(ct$b$one) <- ~lon+lat
> >     coordinates(ct$b$two) <- ~lon+lat
> >
> >     s <- 1:length(ct)
> >     ctply <- list()
> >     for (i in s){
> >      for (j in 1:length(ct[[i]])) {
> >       ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes =
> > sapply(X =
> >     ct[[i]][j],
> >         FUN = function(y) geosphere::centroid(slot(y, "coords"))), no =
> >     ct[[i]][j] )
> >      }
> >     }
> >
> >     Thanks in advance
> >
> >     Regards,
> >     Ariel
> >
> >         [[alternative HTML version deleted]]
> >
> >     _______________________________________________
> >     R-sig-Geo mailing list
> >     [hidden email]
> >     https://stat.ethz.ch/mailman/listinfo/r-sig-geo
> >
> >
> >
>
>         [[alternative HTML version deleted]]
>
> _______________________________________________
> R-sig-Geo mailing list
> [hidden email]
> https://stat.ethz.ch/mailman/listinfo/r-sig-geo
>


--
Vijay Lulla

Assistant Professor,
Dept. of Geography, IUPUI
425 University Blvd, CA-207C.
Indianapolis, IN-46202
[hidden email]
ORCID: https://orcid.org/0000-0002-0823-2522
Webpage: http://vijaylulla.com

        [[alternative HTML version deleted]]

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo
Reply | Threaded
Open this post in threaded view
|

Re: help: Problem getting centroids inside lists

R-sig-geo mailing list
In reply to this post by aestfd
On any R mailing list, whenever you say "it doesn't work", you should always copy exactly what R command you gave, and any error messages.

First notice:

> ct$a$two
SpatialPoints:
     lon lat
[1,] -18  -2
[2,] -16  50
Coordinate Reference System (CRS) arguments: NA

Then compare these:

> coordinates(ct$a$two)
     lon lat
[1,] -18  -2
[2,] -16  50

> coordinates(slot(ct$a$two,'coords'))
     lon lat
[1,] -18  -2
[2,] -16  50

The results are the same. Why are you using the slot() function? There is no need, and it makes it more difficult to understand.


You have assumed the mean() function will give you what you want when there are two points. It doesn't. Try it and see:

> mean( coordinates(ct$a$two))
[1] 3.5

> mean(coordinates(slot(ct$a$two,'coords')))
 [1] 3.5

Replace the mean() function with a function that will give you the "centroid" of two points, however you want to define that centroid. Perhaps the means of the two columns? R has a function for that.

-----------------
In this bit:

ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
                                                    FUN = function(y)

Using X = s is wrong because you haven't defined or created s anywhere. X should be ct.

Also, X = ct[[x]] is wrong. When the first FUN is executed, it will be supplied automatically with the whole of ct$a, then ct$b. Try

ctply <- lapply(X = s, FUN = function(x) sapply(X = x,
                                                    FUN = function(y)

The whole thing is easier to understand and test if you define the functions outside the lapply and sapply calls.

-Don
--
Don MacQueen
Lawrence Livermore National Laboratory
7000 East Ave., L-627
Livermore, CA 94550
925-423-1062
Lab cell 925-724-7509
 
 

On 9/12/18, 11:42 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <[hidden email] on behalf of [hidden email]> wrote:

    I went to a more general approach, that is:
   
    ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
              FUN = function(y) if(length(y)>1) geosphere::centroid(slot(y,
    "coords"))
              else sp::coordinates(slot(y, "coords"))))
   
    But now I want to add the case when they are only two elements. The dataset
    will be:
   
    ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat = c(-20,
    5, 0)),
                        two = data.frame(lon = c(-18, -16), lat = c(-2, 50))),
               b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1, 25,
    5)),
                        two = data.frame(lon = c(-90), lat = c(-1))))
    coordinates(ct$a$one) <- ~lon+lat
    coordinates(ct$a$two) <- ~lon+lat
    coordinates(ct$b$one) <- ~lon+lat
    coordinates(ct$b$two) <- ~lon+lat
   
    And I did the following but it doesn't work:
   
    ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
                                                    FUN = function(y)
    if(length(y)>2) geosphere::centroid(slot(y, "coords"))
                                                    else if (length(y) == 1)
    sp::coordinates(slot(y, "coords"))
                                                    else
    mean(sp::coordinates(slot(y, "coords")))))
   
    I need the result of each element of the list will be a matrix of two rows
    per column (named: one, two). How do I fix it?
   
    Regards,
    Ariel
   
    2018-09-10 17:29 GMT-03:00 MacQueen, Don <[hidden email]>:
   
    > If all of your data frames had enough points then this should work:
    >
    > myfun1 <- function(le) {
    >   list(one=geosphere::centroid(coordinates(le$one)),
    >        two=geosphere::centroid(coordinates(le$two))
    >        )
    > }
    >
    > lapply(ct, myfun1)
    >
    > To handle the one point case, try the following, which I think works with
    > your example data, but is untested if there just two points.
    > It also assumes the data frames are named 'one' and 'two', and will ignore
    > any others. To handle other names, I think you
    > could replace  $one  with  [[1]]  and  $two  with  [[2]]  .
    >
    > myfun <- function(le) {
    >   list(one=if (length(le$one)>1) geosphere::centroid(coordinates(le$one))
    > else coodinates(le$one),
    >        two=if (length(le$two)>1) geosphere::centroid(coordinates(le$two))
    > else coordinates(le$two)
    >        )
    > }
    >
    > lapply(ct, myfun)
    >
    >
    > To see a little bit of what's going on, try
    >
    >   myfun(ct[[1]])
    >   myfun1(ct[[1]])
    >   myfun1(ct[[2]])
    >   myfun(ct[[2]])
    >
    >
    >
    > I would also verify that the length method for objects of class
    > SpatialPoints does return the number of points, as it appears to:
    >
    > > class(ct$a$two)
    > [1] "SpatialPoints"
    > attr(,"package")
    > [1] "sp"
    >
    > > length(ct$a$one)
    > [1] 3
    > > length(ct$a$two)
    > [1] 3
    > > length(ct$a$two)
    > [1] 3
    > > length(ct$b$two)
    > [1] 1
    >
    > --
    > Don MacQueen
    > Lawrence Livermore National Laboratory
    > 7000 East Ave., L-627
    > Livermore, CA 94550
    > 925-423-1062
    > Lab cell 925-724-7509
    >
    >
    >
    > On 9/10/18, 10:56 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <
    > [hidden email] on behalf of [hidden email]>
    > wrote:
    >
    >     Hi everyone,
    >
    >     I have a list of coordinates called "ct" and I want to extract the
    >     centroids of each sublist, but it only works when it has only 3 or more
    >     points. In ct$b$two only has one point; in that case, I would rescue
    > that
    >     point as If it were a centroid.
    >
    >     This is what I did:
    >
    >     library(dplyr)
    >     library(geosphere)
    >
    >     ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat =
    > c(-20,
    >     5, 0)),
    >                         two = data.frame(lon = c(-18, -16, -6), lat =
    > c(-2, 50,
    >     10))),
    >                b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1,
    > 25,
    >     5)),
    >                         two = data.frame(lon = c(-90), lat = c(-1))))
    >
    >     coordinates(ct$a$one) <- ~lon+lat
    >     coordinates(ct$a$two) <- ~lon+lat
    >     coordinates(ct$b$one) <- ~lon+lat
    >     coordinates(ct$b$two) <- ~lon+lat
    >
    >     s <- 1:length(ct)
    >     ctply <- list()
    >     for (i in s){
    >      for (j in 1:length(ct[[i]])) {
    >       ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes =
    > sapply(X =
    >     ct[[i]][j],
    >         FUN = function(y) geosphere::centroid(slot(y, "coords"))), no =
    >     ct[[i]][j] )
    >      }
    >     }
    >
    >     Thanks in advance
    >
    >     Regards,
    >     Ariel
    >
    >         [[alternative HTML version deleted]]
    >
    >     _______________________________________________
    >     R-sig-Geo mailing list
    >     [hidden email]
    >     https://stat.ethz.ch/mailman/listinfo/r-sig-geo
    >
    >
    >
   
    [[alternative HTML version deleted]]
   
    _______________________________________________
    R-sig-Geo mailing list
    [hidden email]
    https://stat.ethz.ch/mailman/listinfo/r-sig-geo
   

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo
Reply | Threaded
Open this post in threaded view
|

Re: help: Problem getting centroids inside lists

aestfd
I understand, but I said "it doesn't work" because it gave an undesired
solution, but I'll try to be more explicit next time.
And I forgot to say that: s  <- 1: length(ct)

And thank you for your advice, but the answer of Vijay Lulla resolved my
problem.

Regards,
Ariel

2018-09-12 17:43 GMT-03:00 MacQueen, Don <[hidden email]>:

> On any R mailing list, whenever you say "it doesn't work", you should
> always copy exactly what R command you gave, and any error messages.
>
> First notice:
>
> > ct$a$two
> SpatialPoints:
>      lon lat
> [1,] -18  -2
> [2,] -16  50
> Coordinate Reference System (CRS) arguments: NA
>
> Then compare these:
>
> > coordinates(ct$a$two)
>      lon lat
> [1,] -18  -2
> [2,] -16  50
>
> > coordinates(slot(ct$a$two,'coords'))
>      lon lat
> [1,] -18  -2
> [2,] -16  50
>
> The results are the same. Why are you using the slot() function? There is
> no need, and it makes it more difficult to understand.
>
>
> You have assumed the mean() function will give you what you want when
> there are two points. It doesn't. Try it and see:
>
> > mean( coordinates(ct$a$two))
> [1] 3.5
>
> > mean(coordinates(slot(ct$a$two,'coords')))
>  [1] 3.5
>
> Replace the mean() function with a function that will give you the
> "centroid" of two points, however you want to define that centroid. Perhaps
> the means of the two columns? R has a function for that.
>
> -----------------
> In this bit:
>
> ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
>                                                     FUN = function(y)
>
> Using X = s is wrong because you haven't defined or created s anywhere. X
> should be ct.
>
> Also, X = ct[[x]] is wrong. When the first FUN is executed, it will be
> supplied automatically with the whole of ct$a, then ct$b. Try
>
> ctply <- lapply(X = s, FUN = function(x) sapply(X = x,
>                                                     FUN = function(y)
>
> The whole thing is easier to understand and test if you define the
> functions outside the lapply and sapply calls.
>
> -Don
> --
> Don MacQueen
> Lawrence Livermore National Laboratory
> 7000 East Ave., L-627
> Livermore, CA 94550
> 925-423-1062
> Lab cell 925-724-7509
>
>
>
> On 9/12/18, 11:42 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <
> [hidden email] on behalf of [hidden email]>
> wrote:
>
>     I went to a more general approach, that is:
>
>     ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
>               FUN = function(y) if(length(y)>1) geosphere::centroid(slot(y,
>     "coords"))
>               else sp::coordinates(slot(y, "coords"))))
>
>     But now I want to add the case when they are only two elements. The
> dataset
>     will be:
>
>     ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60), lat =
> c(-20,
>     5, 0)),
>                         two = data.frame(lon = c(-18, -16), lat = c(-2,
> 50))),
>                b = list(one = data.frame(lon = c(-9, -8, -3), lat = c(-1,
> 25,
>     5)),
>                         two = data.frame(lon = c(-90), lat = c(-1))))
>     coordinates(ct$a$one) <- ~lon+lat
>     coordinates(ct$a$two) <- ~lon+lat
>     coordinates(ct$b$one) <- ~lon+lat
>     coordinates(ct$b$two) <- ~lon+lat
>
>     And I did the following but it doesn't work:
>
>     ctply <- lapply(X = s, FUN = function(x) sapply(X = ct[[x]],
>                                                     FUN = function(y)
>     if(length(y)>2) geosphere::centroid(slot(y, "coords"))
>                                                     else if (length(y) ==
> 1)
>     sp::coordinates(slot(y, "coords"))
>                                                     else
>     mean(sp::coordinates(slot(y, "coords")))))
>
>     I need the result of each element of the list will be a matrix of two
> rows
>     per column (named: one, two). How do I fix it?
>
>     Regards,
>     Ariel
>
>     2018-09-10 17:29 GMT-03:00 MacQueen, Don <[hidden email]>:
>
>     > If all of your data frames had enough points then this should work:
>     >
>     > myfun1 <- function(le) {
>     >   list(one=geosphere::centroid(coordinates(le$one)),
>     >        two=geosphere::centroid(coordinates(le$two))
>     >        )
>     > }
>     >
>     > lapply(ct, myfun1)
>     >
>     > To handle the one point case, try the following, which I think works
> with
>     > your example data, but is untested if there just two points.
>     > It also assumes the data frames are named 'one' and 'two', and will
> ignore
>     > any others. To handle other names, I think you
>     > could replace  $one  with  [[1]]  and  $two  with  [[2]]  .
>     >
>     > myfun <- function(le) {
>     >   list(one=if (length(le$one)>1) geosphere::centroid(
> coordinates(le$one))
>     > else coodinates(le$one),
>     >        two=if (length(le$two)>1) geosphere::centroid(
> coordinates(le$two))
>     > else coordinates(le$two)
>     >        )
>     > }
>     >
>     > lapply(ct, myfun)
>     >
>     >
>     > To see a little bit of what's going on, try
>     >
>     >   myfun(ct[[1]])
>     >   myfun1(ct[[1]])
>     >   myfun1(ct[[2]])
>     >   myfun(ct[[2]])
>     >
>     >
>     >
>     > I would also verify that the length method for objects of class
>     > SpatialPoints does return the number of points, as it appears to:
>     >
>     > > class(ct$a$two)
>     > [1] "SpatialPoints"
>     > attr(,"package")
>     > [1] "sp"
>     >
>     > > length(ct$a$one)
>     > [1] 3
>     > > length(ct$a$two)
>     > [1] 3
>     > > length(ct$a$two)
>     > [1] 3
>     > > length(ct$b$two)
>     > [1] 1
>     >
>     > --
>     > Don MacQueen
>     > Lawrence Livermore National Laboratory
>     > 7000 East Ave., L-627
>     > Livermore, CA 94550
>     > 925-423-1062
>     > Lab cell 925-724-7509
>     >
>     >
>     >
>     > On 9/10/18, 10:56 AM, "R-sig-Geo on behalf of Ariel Fuentesdi" <
>     > [hidden email] on behalf of
> [hidden email]>
>     > wrote:
>     >
>     >     Hi everyone,
>     >
>     >     I have a list of coordinates called "ct" and I want to extract
> the
>     >     centroids of each sublist, but it only works when it has only 3
> or more
>     >     points. In ct$b$two only has one point; in that case, I would
> rescue
>     > that
>     >     point as If it were a centroid.
>     >
>     >     This is what I did:
>     >
>     >     library(dplyr)
>     >     library(geosphere)
>     >
>     >     ct <- list(a = list(one = data.frame(lon = c(-180, -160, -60),
> lat =
>     > c(-20,
>     >     5, 0)),
>     >                         two = data.frame(lon = c(-18, -16, -6), lat =
>     > c(-2, 50,
>     >     10))),
>     >                b = list(one = data.frame(lon = c(-9, -8, -3), lat =
> c(-1,
>     > 25,
>     >     5)),
>     >                         two = data.frame(lon = c(-90), lat = c(-1))))
>     >
>     >     coordinates(ct$a$one) <- ~lon+lat
>     >     coordinates(ct$a$two) <- ~lon+lat
>     >     coordinates(ct$b$one) <- ~lon+lat
>     >     coordinates(ct$b$two) <- ~lon+lat
>     >
>     >     s <- 1:length(ct)
>     >     ctply <- list()
>     >     for (i in s){
>     >      for (j in 1:length(ct[[i]])) {
>     >       ctply[[i]][j] <- ifelse(test = lengths(ct[[i]][1]) > 2, yes =
>     > sapply(X =
>     >     ct[[i]][j],
>     >         FUN = function(y) geosphere::centroid(slot(y, "coords"))),
> no =
>     >     ct[[i]][j] )
>     >      }
>     >     }
>     >
>     >     Thanks in advance
>     >
>     >     Regards,
>     >     Ariel
>     >
>     >         [[alternative HTML version deleted]]
>     >
>     >     _______________________________________________
>     >     R-sig-Geo mailing list
>     >     [hidden email]
>     >     https://stat.ethz.ch/mailman/listinfo/r-sig-geo
>     >
>     >
>     >
>
>         [[alternative HTML version deleted]]
>
>     _______________________________________________
>     R-sig-Geo mailing list
>     [hidden email]
>     https://stat.ethz.ch/mailman/listinfo/r-sig-geo
>
>
>

        [[alternative HTML version deleted]]

_______________________________________________
R-sig-Geo mailing list
[hidden email]
https://stat.ethz.ch/mailman/listinfo/r-sig-geo