ctmm-initiative / ctmm

Continuous-Time Movement Modeling. Functions for identifying, fitting, and applying continuous-space, continuous-time stochastic movement models to animal tracking data.
http://biology.umd.edu/movement.html
47 stars 10 forks source link

Should as.telemetry always return a list even for single object? #8

Closed xhdong-umd closed 7 years ago

xhdong-umd commented 7 years ago

@chfleming I noticed as.telemetry return a single object for single animal, and a list of objects for multiple animals. This means I need to add a check for the input type every time. Previously I can just use this format:

fun_a <- function(tele_objs) {
  if (class(tele_objs) != "list") {
    return(fun_a(list(fun_a)))
  } else {
    ... # real code for list here
}
} 

Today I just noticed my app cannot deal with input data with single animal in the individual plot 3. Turned out the above wrapper is not enough because I have ext_list <- lapply(tele_objs, extent, level = level) which rely on the return result list structure, there will be a name attribute for every item in list, and that name is the animal name. However with single animal input, a simple wrapper with list(tele_objs) will not generate the name attribute this time.

I can add some code to extract the animal name then add it back. Though I'm thinking if it's possible to make the return result consistent, just return a single item list with same structure, including the name of animal.

This is a substantial change which definitely could break a lot of existing code. Though I want to check with you about the possibility and the extent of impacts.

chfleming commented 7 years ago

This is something I have thought about in the past and there are some extra considerations. So far I have been treating single objects and lists of objects as semantically different for my methods. For instance, summary() on a single ctmm object gives you information about the characteristics of that animal's movement, while summary() on a list of ctmm objects does a model selection comparison to tell you which movement models perform better. In the future, ctmm.fit() on a list of telemetry objects will fit a correlated movement model, which is different from lappy(data_list,ctmm.fit). For model fitting now, and most in the future, users need to select out one animal from the telemetry list at a time. Also, most users tend to have consistent behavior in either having many 1-animal CSVs or few many-animal CSVs, so the current setup doesn't really impact users, as far as I have seen. If anything, users are often initially confused that they have to analyze their animals individually and can't use one variogram and model fit on the entire population.

I think the easiest solution for now is to just call an internal function like

telemetry.prepare <- function(data)
{
  # test this way in case data somehow gets demoted by data.frame methods
  if(class(data) == 'telemetry' || class(data) == 'data.frame')
  {
    data <- list(data)
    names(data) <- attr(data[[1]],"info")$identity
  }
  return(data)
}

But I will think about this more.

xhdong-umd commented 7 years ago

I totally understand the huge impact of this. If there is no strong reason we don't have to change the current behavior.

I'll just make a helper function in my app if you don't really need this feature in ctmm. I have the animal name in the identity column of the data frame, so I just need to construct the list better instead of a simple list(tele_objs).

xhdong-umd commented 7 years ago

I added helper function in my app and solved the single animal display problem for plot 3.