Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Create a value associated with a member of each list and store it with that member in R

I have a list of many dataframes, all of the same format. For each member of this list, I would like to generate a spatial extent, and store it with that dataframe (this data is all lat/long data, and I am using functions from the terra package to analyze it). I am not super experienced with working with lists, and so I took the following stab at trying to generate it:

library(terra)
library(dplyr)


lat_1 <- c(23.2, 14.5, 28.6)
lon_1 <- c(12.1, 8.5, 2.2)

lat_2 <- c(89.3, 94.4, 72.3)
lon_2 <- c(45.2, 47, 48.5)

coords_1 <- data.frame(lon_1, lat_1)
coords_2 <- data.frame(lon_2, lat_2)

list_coords <- list(coords_1, coords_2)

write_extent <- function(lon, lat) {
  max_lat <- ceiling(max(lat)) 
  min_lat <- floor(min(lat)) 
  max_lon <- ceiling(max(lon)) 
  min_lon <- floor(min(lon))
  extent <- extent(x = c(max_lat, min_lat, max_lon, min_lon))
}

However, this function has errors, and I can’t conceptualize how I can store the spatial extent that corresponds with each member of the list with that specific list- should I be using mutate()? Should I not be designing a function and rather be using lapply?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

You can do this a couple of different ways. First, you’ll want to make the data frames have the same column names for longitude and latitude lon and lat, but that’s arbitrary. Once you’ve done that, then one way is to produce a new list where each element of the list has both a data frame and an extent object:

library(terra)
library(raster)
library(dplyr)


lat_1 <- c(23.2, 14.5, 28.6)
lon_1 <- c(12.1, 8.5, 2.2)

lat_2 <- c(89.3, 94.4, 72.3)
lon_2 <- c(45.2, 47, 48.5)

coords_1 <- data.frame(lon = lon_1, lat = lat_1)
coords_2 <- data.frame(lon = lon_2, lat = lat_2)

list_coords <- list(coords_1, coords_2)

write_extent <- function(lon, lat) {
  max_lat <- ceiling(max(lat)) 
  min_lat <- floor(min(lat)) 
  max_lon <- ceiling(max(lon)) 
  min_lon <- floor(min(lon))
  extent <- extent(x = min_lat, xmax=max_lat, ymin = min_lon, ymax=max_lon)
  extent
}

res <- lapply(list_coords, function(x){
  list(data=x, extent = write_extent(x$lon, x$lat))
})
res
#> [[1]]
#> [[1]]$data
#>    lon  lat
#> 1 12.1 23.2
#> 2  8.5 14.5
#> 3  2.2 28.6
#> 
#> [[1]]$extent
#> class      : Extent 
#> xmin       : 14 
#> xmax       : 29 
#> ymin       : 2 
#> ymax       : 13 
#> 
#> 
#> [[2]]
#> [[2]]$data
#>    lon  lat
#> 1 45.2 89.3
#> 2 47.0 94.4
#> 3 48.5 72.3
#> 
#> [[2]]$extent
#> class      : Extent 
#> xmin       : 72 
#> xmax       : 95 
#> ymin       : 45 
#> ymax       : 49

In the output above, you could get the data for the first object with res[[1]]$data and the extent for the first object with res[[1]]$extent. Or you could get a list of all the extents with lapply(res, function(x)x$extent). Another option would be to store the extent as an attribute of the data. This way, it always follows the data around:


res <- lapply(list_coords, function(x){
  e <- write_extent(x$lon, x$lat)
  attr(x, "extent") <- e
  x
})
res
#> [[1]]
#>    lon  lat
#> 1 12.1 23.2
#> 2  8.5 14.5
#> 3  2.2 28.6
#> 
#> [[2]]
#>    lon  lat
#> 1 45.2 89.3
#> 2 47.0 94.4
#> 3 48.5 72.3

You don’t see the extent when you print the data frame, but you can retrieve it either for a single data frame with:

attr(res[[1]], "extent")
#> class      : Extent 
#> xmin       : 14 
#> xmax       : 29 
#> ymin       : 2 
#> ymax       : 13

Or for all of them with:

lapply(res, function(x)attr(x, "extent"))
#> [[1]]
#> class      : Extent 
#> xmin       : 14 
#> xmax       : 29 
#> ymin       : 2 
#> ymax       : 13 
#> 
#> [[2]]
#> class      : Extent 
#> xmin       : 72 
#> xmax       : 95 
#> ymin       : 45 
#> ymax       : 49

Created on 2022-12-08 by the reprex package (v2.0.1)

While I think it’s a bit less conventional to set object attributes, this answer suggests it is not bad practice to do so.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading