ptitle / epm

An R package for the calculation of taxonomic, phenotypic and phylogenetic metrics across grid cells.
GNU General Public License v3.0
12 stars 3 forks source link

gridID in the tableFromEpmGrid output #4

Closed Labarcena-Jessica closed 7 months ago

Labarcena-Jessica commented 7 months ago

Hello Pascal,

I was wondering if there is any way to get the gridID and add it to the df from the tableFromEpmGrid function. The problem is that I use the tableFromEpmGrid output to run GAM models, and now I want to update my grid cell by adding the predicted values from the model and mapping it. This is what I was trying to do, but I need help getting it to work.

get the grid object

df_grid <- epm_obj[[1]]

get the centroid values for each cell

templateCentroids <- sf::st_centroid(sf::st_geometry(df_grid$gridTemplate)) coord_grid <- sf::st_coordinates(templateCentroids )

What I noticed is that the values I get are not in correspondence with the X and Y on the tableFromEpmGrid output. I checked the projection and made sure all objects had the same one, but still nothing.

I would appreciate your input.

Thank you!

Jessica

ptitle commented 7 months ago

Hi Jessica,

I agree that returning the grid cell id's would be useful, and maybe I'll add that in to the R package. In the meantime, it's pretty straightforward to do this. The reason that the coordinates were not matching cell centroids is because the points are randomly sampled in the tableFromEpmGrid function, not selected from the set of possible cell centroids.

Here is how to get the cell ID's, depending on which type of grid cell you are working with:

library(epm)
library(sf)
library(terra)

# If working with hexagonal cells

tamiasEPM
tamiasEPM <- addPhylo(tamiasEPM, tamiasTree)
tamiasEPM <- addTraits(tamiasEPM, tamiasTraits)
morphoDisp <- gridMetrics(tamiasEPM, metric='disparity')
meanPat <- gridMetrics(tamiasEPM, metric='meanPatristic')

df_grid <- tamiasEPM[[1]]

xx <- tableFromEpmGrid(tamiasEPM, morphoDisp, meanPat, n = 100, minTaxCount = 2)

# convert the xy to spatial sf object
xxPts <- st_geometry(st_as_sf(xx, coords = c('x', 'y'), crs = st_crs(df_grid)))

# tests the intersection of each point with each grid cell.
# this returns a list, where each entry is the index of the grid cell that intersects with that point.
ptCheck <- st_intersects(xxPts, df_grid)

# add it back into the table.
xx$gridCell <- unlist(ptCheck)

head(xx)

# if working with square cells

tamiasEPM2 <- createEPMgrid(tamiasPolyList, resolution = 50000,
    cellType = 'square', method = 'centroid')

tamiasEPM2 <- addPhylo(tamiasEPM2, tamiasTree)
tamiasEPM2 <- addTraits(tamiasEPM2, tamiasTraits)
morphoDisp <- gridMetrics(tamiasEPM2, metric='disparity')
meanPat <- gridMetrics(tamiasEPM2, metric='meanPatristic')

df_grid <- tamiasEPM2[[1]]

xx <- tableFromEpmGrid(tamiasEPM2, morphoDisp, meanPat, n = 100, minTaxCount = 2)

# easier with square grids and the terra package
xx$gridCell <- cellFromXY(df_grid, xx[, c('x', 'y')])

head(xx)
Labarcena-Jessica commented 7 months ago

Thank you very much for your help, Pascal. That worked perfectly. I agree it will be helpful to include the grid ID in the output dataframe from tableFromEpmGrid.

On another note, while working with the function rasterToGrid() I found that it doesn't work with lapply. I have a list of 58 rasters and wanted to run the rasterToGrid, but it didn't work. I came up with a workaround by adapting the code of this function to work for a list of rasters.

df_values <- lapply(abundance_cropped, terra::extract, terra::vect(epm_obj[[1]]), list = FALSE)

calculating mean values per cell

newvals_abu <- lapply(df_values, function(x) aggregate(x , by = list(x$ID), FUN = mean))

getting the values and geographical coordinates of each cell.

abu_cell <- lapply(newvals_abu, function(x) sf::st_sf( vals = x[,3], geometry = sf::st_geometry(epm_obj[[1]])))

After this, I was able to run the tableFromEpmGrid function on the list of updated grids and emp object using lapply.

Is there any other way I can do this? Otherwise, it will be nice to update the rasterToGrid() function so it can work with a list of rasters.

This package is awesome for grid analysis.

Thank you for your help!

Jessica

ptitle commented 7 months ago

Hi Jessica,

I've now pushed an update so that the github version of EPM can now return grid cell ID's for tableFromEpmGrid(). Can you test it out for me?

As for your question about rasterToGrid(), I also made a small update so that it can now properly handle multi layer spatRasters.

library(epm)
library(terra)

# generate a multi-layer SpatRaster
env <- rast(vect(tamiasEPM[[1]]), resolution = 100000, nlyrs = 5)
values(env[[1]]) <- sample(1:100, ncell(env), replace = TRUE)
values(env[[2]]) <- sample(1:100, ncell(env), replace = TRUE)
values(env[[3]]) <- sample(1:100, ncell(env), replace = TRUE)
values(env[[4]]) <- sample(1:100, ncell(env), replace = TRUE)
values(env[[5]]) <- sample(1:100, ncell(env), replace = TRUE)
env

# this now returns a list of items if the input was multi-layer.
newgrid <- rasterToGrid(env, target = tamiasEPM, fun = 'mean')

As for using lapply():

# convert the above multi-layer SpatRaster to a list of rasters
env2 <- lapply(1:nlyr(env), function(x) env[[x]])

newgrid2 <- lapply(env2, function(x) rasterToGrid(x, target = tamiasEPM, fun = 'mean'))

Does that make sense? Is this now doing what you were hoping?

Labarcena-Jessica commented 7 months ago

Hi Pascal,

I suspect tableFromEpmGrid is not getting the gridCell ID properly. It produces a gridCellID column, but it has just the same numbers as the rowname, not the real gridID in the epm grid object. Also, for the function to work with the id = TRUE argument the epmObject needs to be the first argument in the function. If I run it with the epmObject as the second argument I get the following error. epm_test <- tableFromEpmGrid( t1, epm_ON_1km, id = TRUE) Error in (function (classes, fdef, mtable) : unable to find an inherited method for function ‘cellFromXY’ for signature ‘"integer", "data.frame"’

The rasterToGrid() function is working as expected when I use a SpatRaster object. I don't need to use lapply anymore as this solves the problem.

I am happy to run any other test.

Thank you!

Jessica

ptitle commented 7 months ago

That was a good point about ordering of the inputs. That's fixed now. To me, it seems to be returning the proper id's. If you are still seeing this behavior (incorrect id), if you can create something reproducible for me to run, that would be very helpful.

Thanks for helping me troubleshoot this!

Labarcena-Jessica commented 7 months ago

I am using an sf object. Could it be that? How can I better share the .RDS files for you to try?

ptitle commented 7 months ago

If you could save the objects as .rds files and send them to me (pascal.title[at]stonybrook.edu), along with a short script that replicates the problem, then I can replicate what you are seeing.

ptitle commented 7 months ago

This is now resolved. tableFromEpmGrid() with id = TRUE seems to return the correct grid cell indices.