Trackage / trip

trip package development
http://trackage.github.io/trip/
12 stars 2 forks source link

wrapper for algorithm logic #27

Closed mdsumner closed 5 years ago

mdsumner commented 5 years ago

Here's a trip_sda filter function and example that works with the same interface as argosfilter. We necessarily have to remove locations that don't make sense (out of order, duplicate times) - internally argosfilter swallows these with an eps values.

  library(argosfilter)
data(seal)
## fix the data first (there is only one trip here, no multiples in argosfilter)
seal <- seal[order(seal$dtime), ]
bad <- c(FALSE, !diff(unclass(seal$dtime)) > 0)
seal <- seal[!bad, ]

# The algorithm first removes all locations with
# location class Z (-9), which are the points for which the location
# process failed. 
# (there aren't any Zs here, but for example) 
bad2 <- grepl("z", lc, ignore.case = TRUE)
#> Error in grepl("z", lc, ignore.case = TRUE): object 'lc' not found
seal <- seal[!bad2, ]
#> Error in `[.data.frame`(seal, !bad2, ): object 'bad2' not found
lat<-seal$lat
lon<-seal$lon
dtime<-seal$dtime
lc<-seal$lc
# filter by speed only
mfilter<-vmask(lat,lon,dtime,2)
# filter data using sdafilter
cfilter<-sdafilter(lat, lon, dtime, lc)

trip_sda <- function(lat, lon, dtime, vmax = 2, ang = c(15, 25), 
                     distlim = c(2500,5000), id = "1") {
  ## basic checks
  badlat <- any(is.na(lat))
  badlon <- any(is.na(lon))
  badtime <- any(is.na(dtime))
  baddt <- any(!diff(unclass(dtime)) > 0)
  if (badlat) stop("missing lat value/s")
  if (badlon) stop("missing lon value/s")
  if (badtime) stop("missing dtime value/s")
  if (baddt) stop("dtime not in order and/or contains duplicates")

  if (length(id) > 1) {
    if (!length(id) == length(lat)) stop("length of id must be 1 (for a single trip) or the same length as lat, lon, dtime (defining multiple trips)")
  }
  df <- data.frame(lon = lon, lat = lat, time = dtime, id = id)
  sp::coordinates(df) <- c("lon", "lat")
  sp::proj4string(df) <- "+init=epsg:4326"
  df <- trip::trip(df, c("time", "id"))
  ## trip works in km and km/h (don't judge me)
  trip::sda(df, smax = vmax * 3.6, ang = ang, distlim = distlim/1000)
}

sda <- trip_sda(lat, lon, dtime, vmax = 2, id = 1)
op <- par(mfrow = c(2, 1))
plot(dtime, lon, cex = 0.4, pch = 19);lines(dtime[sda], lon[sda], col = "firebrick", lwd = 5);lines(dtime[cfilter == "not"], lon[cfilter == "not"])
plot(dtime, lat, cex = 0.4, pch = 19);lines(dtime[sda], lat[sda], col = "firebrick", lwd = 5);lines(dtime[cfilter == "not"], lat[cfilter == "not"])

par(op)

Created on 2019-04-03 by the reprex package (v0.2.1)

More ideal would be to remove any algorithm logic from trip (speed, angle filters, time spent, dupe time fudges, the sims, etc and make then complietely generic in a function with no formal classes, with lon, lat, time, [group] function inputs that any package could use.

mdsumner commented 5 years ago

Ping @jmlondon fyi

jmlondon commented 5 years ago

Thanks for this, @mdsumner. Even more ideal (at least for my own selfish workflow) would be an sda filter that I could pass an sf points object (in any projection) and get back an sf object with records to remove indicated.

mdsumner commented 5 years ago

Use st_cordinates to get the raw x,y values. I'd be interested in seeing the way you call argosfilter now