Manually specifying common grid to allow overlap comparison

8 views
Skip to first unread message

Sam Langlois

unread,
Nov 18, 2025, 7:26:55 AM (9 days ago) Nov 18
to ctmm R user group
Hi,

I'm working with a seabird GPS dataset which has been classified into three behaviours, as well as into day and night. I'm trying to carry out UD overlap comparisons at the pop level (following pkde) between different behaviours, as well as between day and night. 

Due to having multiple years of data, I currently use a for loop to subset the specific year-behaviour-day/night combination I want to calculate UDs for. However, I can't use the overlap function due to inconsistent grids. Can I manually specify a grid resolution within the akde function so all outputs are on this grid before running pkde()? Creating a large list of of all the telemetry objects I am interested in so they can be passed through akde together to achieve the same grid res would be too memory intensive.

Many thanks!

Sam Langlois

unread,
Nov 19, 2025, 12:26:34 PM (7 days ago) Nov 19
to ctmm R user group
Hi Chris,

Just to follow up on this, this is the approach I am taking to specify a common grid, although I still get the same error message about grids being inconsistent. I tried including/excluding the grid argument from the pkde function but nothing changes. Any thoughts?

I first estimated UDs for a single individual to use as a reference grid.

DATA <- as.telemetry(
  data,
  timeformat = "auto",
  timezone = "UTC",
  projection=  "+proj=merc +lon_0=0 +k=1 +datum=WGS84 +units=m +no_defs"  ,
  dt.hot = NA,
  timeout = Inf,
  na.rm = "row",
  mark.rm = FALSE,
  keep = FALSE,
  drop = TRUE
)
grid_ref_tele <- DATA[[5]]

guess <- ctmm.guess(grid_ref_tele, interactive = FALSE)
FITS <- ctmm.select(grid_ref_tele, guess)

dt <- 5 %#% 'min' 
GRID_REF_UD <- akde(grid_ref_tele,FITS,dt=dt, weights=FALSE,trace=TRUE)  # make individual UD to use as grid reference

I then run the following loop which produces UDs from several individuals for several years and stores the PKDEs in a list (I've removed some of the code for clarity)

for(species_s in species_list){
 
  # Filter by species
  species_filter <- all_states_filtered %>% filter(species == species_s)
 
  for(year_y in unique(species_filter$Year)){
   
    # Filter by year
    year_filter <- species_filter %>% filter(Year == year_y)
   
    # Convert to telemetry objects (one per individual)
    DATA <- as.telemetry(
      year_filter,
      timeformat = "auto",
      projection=  "+proj=merc +lon_0=0 +k=1 +datum=WGS84 +units=m +no_defs"  ,
      timezone = "UTC",
      dt.hot = NA,
      timeout = Inf,
      na.rm = "row",
      mark.rm = FALSE,
      keep = FALSE,
      drop = TRUE
    )
   
    # ===========================
    # FIT INDIVIDUAL MODELS USING lapply
    # ===========================
    FITS <- lapply(DATA, function(x){
      guess <- ctmm.guess(x, interactive = FALSE)
      ctmm.select(x, guess)
    })
   
    dt <- 5 %#% 'min' # from dt.plot
   
    UDS <- akde(DATA,FITS,weights=FALSE, dt = dt,trace=TRUE, grid=GRID_REF_UD) # make individual IDs, takes c. 30 mins/year/species
   
     PKDE <- pkde(DATA, UDS, kernel="individual", grid=GRID_REF_UD, weights = FALSE) # make population UDs
   
    all_PKDE_list <- c(all_PKDE_list, list(PKDE)) #save PKDEs in list
    
  }
}

all_PKDEs_overlaps_95 <- overlap(all_PKDE_list, method="Bhattacharyya", level=0.95, debias=T)
Error in grid.intersection(UD) : Inconsistent grid resolutions.

Thanks!
Sam

Allie Anderson

unread,
Nov 19, 2025, 3:24:44 PM (7 days ago) Nov 19
to Sam Langlois, ctmm R user group
Hi Sam,

Just responding in case this option is helpful to you. Chris might have a better option. Here's what I have been doing:

## 6oo) CREATE CONSISTENT GRID FOR ALL INDIVIDUALS ####
grid_extent <- ctmm::extent(tlm_lst)  

# GET X AND Y LIMS FOR BOUNDING BOX:
x_range <- diff(grid_extent$x)
y_range <- diff(grid_extent$y)

# Add buffer factor:
buffer_factor <- 0.30 # increased by 30% to add more space if akdes and CIs are larger. May not need this much

# Multiply by buffer factor
buffered_extent <- list(
  x = c(grid_extent$x[1] - x_range * buffer_factor,
      grid_extent$x[2] + x_range * buffer_factor),
  y = c(grid_extent$y[1] - y_range * buffer_factor,
      grid_extent$y[2] + y_range * buffer_factor))

# DEFINE GRID RESOLUTION:
res <- 100  # in meters
xseq <- seq(buffered_extent$x[1], buffered_extent$x[2], by = res)
yseq <- seq(buffered_extent$y[1], buffered_extent$y[2], by = res)
shared_grid <- list(x = xseq, y = yseq)

## 6a) CREATE AKDES BASED ON TOP MODEL FOR ALL ####
akde_lst <- purrr::map2(tlm_lst, ctmm_fit_lst,
            ~akde(.x, .y[[1]], #top model
                 grid = shared_grid)) 

--
You received this message because you are subscribed to the Google Groups "ctmm R user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ctmm-user+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/ctmm-user/4789f145-b7ea-429f-a6c6-f5e5d4e83ec6n%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages