GithubHelp home page GithubHelp logo

mablab / sftrack Goto Github PK

View Code? Open in Web Editor NEW
53.0 12.0 2.0 15.06 MB

sftrack: Modern classes for tracking and movement data

Home Page: https://mablab.org/sftrack/

License: Other

HTML 92.80% R 7.16% JavaScript 0.04%
rstats-package trajectory tracking-data movement

sftrack's Introduction

sftrack: Modern classes for tracking and movement data

Project Status: Active - The project has reached a stable, usable state and is being actively developed. Licence CRAN Status CRAN downloads

R-CMD-check

sftrack provides modern classes for tracking and movement data, relying on sf spatial infrastructure. Tracking data are made of tracks, i.e. series of locations with at least 2-dimensional spatial coordinates (x,y), a time index (t), and individual identification (id) of the object being monitored; movement data are made of trajectories, i.e. the line representation of the path, composed by steps (the straight-line segments connecting successive locations). sftrack is designed to handle movement of both living organisms and inanimate objects.

data definitions

The development and design of the sftrack package follow three simple principles:

  1. Minimal and focused: this is basically the Unix philosophy. Do a simple thing, and do it well. The scope of the package is limited (see above), with as few dependencies as possible;
  2. User-friendly: sftrack is designed to be as easy to use as familiar R structures like data.frames and sf objects. sftrack objects are tidy, and follow the idea that rows are records (locations) and columns are variable (following the semantics of tracking and movement data);
  3. Flexible and extensible: sftrack is meant first for users to use on their data, but also directly designed to address other developers’ needs for their own tracking packages.

Getting started

To get started, install sftrack directly from CRAN, or check the development version on GitHub with the remotes package:

# To install the stable version from CRAN
install.packages("sftrack")

# To install the dev version with built vignettes
remotes::install_github("mablab/sftrack", ref = "dev", build_vignettes = TRUE)

The dev version is updated much more frequently and should pass the majority of CRAN checks. However, if you install the dev version, understand it may still contain some bugs. Please submit any bug you find to the issues page.

A minimal introduction to sftrack and sftraj objects

The easiest way to create an sftrack object is to start from a data.frame with all information as columns, typically the raw data extracted from telemetry devices:

library("sftrack")
data(raccoon)
raccoon$timestamp <- as.POSIXct(as.POSIXlt(raccoon$timestamp, tz = "EST5EDT"))
head(raccoon)
#>   animal_id latitude longitude           timestamp height hdop vdop fix
#> 1   TTP-058       NA        NA 2019-01-18 19:02:30     NA  0.0  0.0  NO
#> 2   TTP-058 26.06945 -80.27906 2019-01-18 20:02:30      7  6.2  3.2  2D
#> 3   TTP-058       NA        NA 2019-01-18 21:02:30     NA  0.0  0.0  NO
#> 4   TTP-058       NA        NA 2019-01-18 22:02:30     NA  0.0  0.0  NO
#> 5   TTP-058 26.06769 -80.27431 2019-01-18 23:02:30    858  5.1  3.2  2D
#> 6   TTP-058 26.06867 -80.27930 2019-01-19 00:02:30    350  1.9  3.2  3D

In order to convert your raw data into an sftrack object, use the function as_sftrack(). The function requires the three main elements of tracking data:

  • coordinates of the locations in at least the x and y axes (can be UTM, lat/long, etc., with projection provided in crs);
  • timestamps of the locations as POSIXct (or as integer);
  • grouping information (referred to as a “groups”), providing at least the identity of each individual.
my_sftrack <- as_sftrack(
  data = raccoon,
  coords = c("longitude","latitude"),
  time = "timestamp",
  group = "animal_id",
  crs = 4326)
head(my_sftrack)
#> Sftrack with 6 features and 10 fields (3 empty geometries) 
#> Geometry : "geometry" (XY, crs: WGS 84) 
#> Timestamp : "timestamp" (POSIXct in EST5EDT) 
#> Groupings : "sft_group" (*id*) 
#> -------------------------------
#>   animal_id latitude longitude           timestamp height hdop vdop fix
#> 1   TTP-058       NA        NA 2019-01-18 19:02:30     NA  0.0  0.0  NO
#> 2   TTP-058 26.06945 -80.27906 2019-01-18 20:02:30      7  6.2  3.2  2D
#> 3   TTP-058       NA        NA 2019-01-18 21:02:30     NA  0.0  0.0  NO
#> 4   TTP-058       NA        NA 2019-01-18 22:02:30     NA  0.0  0.0  NO
#> 5   TTP-058 26.06769 -80.27431 2019-01-18 23:02:30    858  5.1  3.2  2D
#> 6   TTP-058 26.06867 -80.27930 2019-01-19 00:02:30    350  1.9  3.2  3D
#>       sft_group                   geometry
#> 1 (id: TTP-058)                POINT EMPTY
#> 2 (id: TTP-058) POINT (-80.27906 26.06945)
#> 3 (id: TTP-058)                POINT EMPTY
#> 4 (id: TTP-058)                POINT EMPTY
#> 5 (id: TTP-058) POINT (-80.27431 26.06769)
#> 6 (id: TTP-058)  POINT (-80.2793 26.06867)
summary_sftrack(my_sftrack)
#>     group points NAs          begin_time            end_time length_m
#> 1 TTP-041    223   0 2019-01-18 19:02:30 2019-02-01 18:02:07 10212.55
#> 2 TTP-058    222   0 2019-01-18 19:02:30 2019-02-01 18:02:30 26893.27

While sftrack objects contain tracking data (locations), they can easily be converted to movement data (with a step model instead) with as_sftraj:

my_sftraj <- as_sftraj(my_sftrack)
head(my_sftraj)
#> Sftraj with 6 features and 10 fields (3 empty geometries) 
#> Geometry : "geometry" (XY, crs: WGS 84) 
#> Timestamp : "timestamp" (POSIXct in EST5EDT) 
#> Grouping : "sft_group" (*id*) 
#> -------------------------------
#>   animal_id latitude longitude           timestamp height hdop vdop fix
#> 1   TTP-058       NA        NA 2019-01-18 19:02:30     NA  0.0  0.0  NO
#> 2   TTP-058 26.06945 -80.27906 2019-01-18 20:02:30      7  6.2  3.2  2D
#> 3   TTP-058       NA        NA 2019-01-18 21:02:30     NA  0.0  0.0  NO
#> 4   TTP-058       NA        NA 2019-01-18 22:02:30     NA  0.0  0.0  NO
#> 5   TTP-058 26.06769 -80.27431 2019-01-18 23:02:30    858  5.1  3.2  2D
#> 6   TTP-058 26.06867 -80.27930 2019-01-19 00:02:30    350  1.9  3.2  3D
#>       sft_group                       geometry
#> 1 (id: TTP-058)                    POINT EMPTY
#> 2 (id: TTP-058)     POINT (-80.27906 26.06945)
#> 3 (id: TTP-058)                    POINT EMPTY
#> 4 (id: TTP-058)                    POINT EMPTY
#> 5 (id: TTP-058) LINESTRING (-80.27431 26.06...
#> 6 (id: TTP-058) LINESTRING (-80.2793 26.068...

Both objects can easily be plotted with base R plot functions, which highlights the fundamental difference between tracking and movement data (sftrack on the left; sftraj on the right):

plot(my_sftrack, main = "Tracking data (locations)")
plot(my_sftraj, main = "Movement data (steps)")

Roadmap

  • Data class converters from the main tracking packages, such as move::Move and trackeR::trackeRdata, integrated into as_sftrack;
  • More plotting options for tracks and trajectories (in base R and ggplot2);
  • Provide Gantt chart-like or chronogram-like graphs;
  • Dynamic exploration of trajectories.

How can you help?

  1. Submit any bug you find to the issues page;
  2. Address open questions (see below);
  3. Contribute use cases (see below).

Address open questions: We need your feedback!

While the foundations of the package are now pretty solid, we are still dealing with open questions about several aspects of the package, including the names of sftrack variables (e.g. coordinates, timestamps, id and error), the structure of the grouping factor, or the structure of the error term.

If you have strong opinions or simply want to help on the technical side, we invite you to comment on those open issues here.

Contribute use cases: We need your feedback!

We also need to precisely understand what is expected from such a package. The idea here is to collect all possible use cases for a trajectory object in R. We know they are multiple, and will contribute our own use cases — however, we want sftrack to be as useful as possible, and to act as a center piece for movement in R, so we need you to tell us how you would use it. In other words, we want to understand what you expect from such a package, as a user or as a developer. For this, we ask you to fill out special issues in the GitHub tracker of the package, following the ‘Use case’ template.

Use cases do not need to be very complicated, but need to present a specific use in human terms, the technical requirements associated to it, and the input and output of the use case. Such use case could look like this:

[Use case] Amazing plot for trajectory

Use case:

Plot a trajectory using my special_trajplot function, which shows [something amazing].

Requirements:

  • spatial coordinates (x,y) as geographic coordinates with projection information

  • a time (t) as POSIXt object, ordered in time

  • information that identifies individuals (e.g. animal) for each location

  • data associated to each location directly accessible

Input: a sftrack object

Output: a plot with [something amazing] about the trajectory

Additional information: See my special_trajplot function here [with link].

Another example could be like this:

[Use case] Fill in missing locations in a sequence

Use case: Fill in the missing locations of a trajectory that contains spatial or temporal gaps. (for instance coming from GPS with failed fixes); In other words add in the missing values of a trajectory, i.e. timestamps with no geographic coordinates.

Requirements:

  • a time (t) as POSIXt object, ordered in time

  • information that identifies sequences of locations (optional, if several sequences), which could be different circuits of one individual, or different individuals, etc.

  • sftrack should be capable of handling/storing missing values

Input: a sftrack object

Output: a sftrack object with additional timestamps for gaps (but otherwise identical in every way to the original sftrack)

Additional information: See adehabitatLT::setNA, which does exactly that on ltraj objects.

sftrack's People

Contributors

basille avatar birderboone avatar rociojoo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sftrack's Issues

Elements of an 's_group' should be atomic

Simple example from the vignette:

singlegroup <- make_s_group(list(id = "TTP_058", month = 4))
str(singlegroup)

Which works as expected. However, I can also have vectors or lists of length >1 for each variable, e.g.:

singlegroup <- make_s_group(list(id = "TTP_058", month = list(a = 1, b = 2)))
str(singlegroup)

This also works with no error, but defeats the purpose of the individual identification. I think the structure should be stricter and only allow vectors of length 1 (or other things that can be coerced to a vector of length 1).

Messing up steps with step_metrics?

This is what I did:
sim_sftrack <- as_sftrack( data = sim_tracks_df, coords = c("x","y"), time = "time", burst = "group_track" ) sim_metrics <- step_metrics(sim_sftrack)

then
> head(sim_metrics) dx dy dist dt abs_angle speed sftrack_id 1 -4.552723 8.380473 2.0975096 9 2.068445 0.233056625 1-1_1 112 -8.925107 15.603843 0.7150057 18 2.090359 0.039722537 1-1_2 223 -16.392981 26.762819 0.8255781 27 2.120377 0.030576968 1-1_3 261 -20.730838 33.826227 0.0656693 36 2.120620 0.001824147 1-1_4 272 -28.143437 48.727325 0.3345839 45 2.094560 0.007435198 1-1_5 283 -31.249733 54.404988 0.3203247 54 2.092173 0.005931940 1-1_6

Matt has the dataset. I think that it is doing weird stuff, changing the order of rows unnecessarily, because the time variable/column is not in a posixct format as it is just a count. It's just a hunch. But I think that the function should account for a case like this one.

[Use case] Visually cleaning a trajectory

Use case:
Being able to plot the trajectory of an animal. Then visually select outliers and being able to edit the information linked with these location fixes.

Requirements:
spatial coordinates (x,y) as geographic coordinates with projection information
a time (t) as POSIXt object, ordered in time
A quality information: being able to easily 'tag' fixes that are obviously outliers or result of a malfunction of the collar.
A graphic interface to directly click on the fixes to edit the field

Input:
sftraj object with a field 'quality'

Output:
same sftraj as input, but the quality field updated.

Additional information:

[Use case] Compute geometric parameters of steps

Use case:
Trajectories are defined as series of steps; inherent to this are the geometric parameters of each step (in addition to geographic and time coordinates): increments in X and Y direction, step length, absolute and relative (turning) angle, net square displacement (NSD) from a reference point.

Requirements:

  • Geometric parameters should only be computed on demand: for instance, if subsetting the trajectory or adding missing data (among other examples), the previously computed parameters should remain unchanged. However, recomputation should be allowed.
  • It should be possible to compute each parameter independently (i.e. only turning angles or NSD), but also several (or all) at once.

Input:
A sftraj object.

Output:
A sftraj object with additional columns for each parameter. The names of these columns could be defined by the user with sane standard.

Additional information:
Does this depend on projection? Also check creation (as.ltraj) and recomputation (rec) of ltraj objects in adehabitatLT.

upcoming sf breaks sftracks

with:

* checking re-building of vignette outputs ... ERROR
Error(s) in re-building vignettes:
--- re-building ‘sftrack1_overview.Rmd’ using rmarkdown
Quitting from lines 245-249 (sftrack1_overview.Rmd) 
Error: processing vignette 'sftrack1_overview.Rmd' failed with diagnostics:
arguments have different crs
--- failed re-building ‘sftrack1_overview.Rmd’

--- re-building ‘sftrack2_reading.Rmd’ using rmarkdown
Quitting from lines 129-141 (sftrack2_reading.Rmd) 
Error: processing vignette 'sftrack2_reading.Rmd' failed with diagnostics:
arguments have different crs
--- failed re-building ‘sftrack2_reading.Rmd’

--- re-building ‘sftrack3_workingwith.Rmd’ using rmarkdown
Quitting from lines 25-44 (sftrack3_workingwith.Rmd) 
Error: processing vignette 'sftrack3_workingwith.Rmd' failed with diagnostics:
arguments have different crs
--- failed re-building ‘sftrack3_workingwith.Rmd’

--- re-building ‘sftrack4_groups.Rmd’ using rmarkdown
--- finished re-building ‘sftrack4_groups.Rmd’

--- re-building ‘sftrack5_spatial.Rmd’ using rmarkdown
Quitting from lines 21-35 (sftrack5_spatial.Rmd) 
Error: processing vignette 'sftrack5_spatial.Rmd' failed with diagnostics:
arguments have different crs
--- failed re-building ‘sftrack5_spatial.Rmd’

SUMMARY: processing the following files failed:
  ‘sftrack1_overview.Rmd’ ‘sftrack2_reading.Rmd’
  ‘sftrack3_workingwith.Rmd’ ‘sftrack5_spatial.Rmd’

Error: Vignette re-building failed.
Execution halted

* checking PDF version of manual ... OK
* DONE

Status: 1 ERROR
See
  ‘/tmp/sftrack.Rcheck/00check.log’
for details.

it seems that the following NEWS.md item is responsible:

  • c.sfc() (and, consequently, dplyr::bind_rows()) gives an error if components have different CRS; #1884

see r-spatial/sf#1884

README example doesn't run

I tried the README example with both github master and dev versions, but get:

> my_sftrack <- as_sftrack(
+   data = raccoon,
+   coords = c("longitude","latitude"),
+   time = "timestamp",
+   burst = "animal_id",
+   crs = "+init=epsg:4326")
Error in check_names_exist(data, group) : id not found in data frame

Active burst structure

Related to the burst strucutre is how the active burst feature works.

We wanted to be able to create many grouping options, and switch between them as necessary. We wanted to be able to check each grouping vector in advanced so we could switch between groups quicker. This was the creation of the active burst. It currently resides in the 'ind_bursts' so that we can calculate an index id for use in subsetting rows.

Should this be changed to how dplyr works where there is an actively maintained grouping data.frame attribute that describes which row numbers each group resides in? If this was the case, then active burst would move to an attribute at the multi_burst level. The current structure is less complicated as we just subset by this index (the label attribute), how ever it is recalculated everytime the active_burst changes, which could be more inefficient than having a data.frame attribute of the grouping indexes calculated when first creating a burst column.

Names of the row level and column level grouping class.

Similar to the sfc and sfg classes in sf, our grouping class ('burst') has two main classes:

  • The single row level, one list object that contains all the named grouping levels. Currently called a 'ind_burst' (standing for individual burst).
  • The column level, a column of a collection of the single row level objects. Currently called a 'multi_burst'.

Given we retain this structure what should the classes be named that is both short and understandable to their purposes. It has been suggested to use a similar naming structure as the sf geometry column and use something akin to 'burstc' and 'burstg' for each level.

This is somewhat dependent on if we change from calling it a burst to a group, but the idea remains the same.

Burst structure

This is an open discussion on the technical structure of bursts, otherwise known as 'groups'.

Currently there is two tier levels for bursts, a multi_burst (column level) and an ind_burst (a row level). This was originally created so we could have more control over each level. If some one wants to change the the grouping categories of a single row, they'd be able to. A lot like how the sfg/sfc structure works. But is this the most parsimonious solution to what we're trying to accomplish

Is it easier to just have a grouping attribute instead that signals the column names used in grouping, like how dplyr::group_by works? My original argument is that our grouping column requires a lot more boundaries around it than what a a group_by column is (i.e It has a naming structure, an active burst, requirements for what class the data are in, etc.). But we could theoretically have checks that continuously checks that these columns adhere to our rules. This might be more complicated, and I'm not sure which option is the most right.

as_sftrack fails when burst column is already named 'burst'

This was submitted to me by @rociojoo , and Ill post it here for a record. When the raw data already has a column named 'burst', sftrack is(was) not set up to overwrite it correctly. Instead the burst column is being renamed to 'burst.1'.

Downstream this also means sftrack does not always read the attr(x, 'burst'), and instead occasionally still does data$burst. This would be a good time for me to check that all data$burst have been changed too data[[attr(x,'burst')]]. Also its possible that when this does occur the name of the column ('burst.1') is also not getting stored properly in the 'burst' attribute of the sftrack.

I wont get to this change for a couple of days, however.

[Use case] Aircraft trajectories

Use case:
The massive availability of crowdsourced ADS-B position reports from parties such as
flightradar24 (commercial), FlightAware (commercial), ADSBx (free for non-commercial/research) or OpenSky Network (free for reseach) makes it possible to study 4D aircraft trajectories with an unprecedented spatial coverage and accuracy.

Requirements:
What are the technical requirements needed to achieve this use case. I.e an ordered time series and a set of geographic coordinates are required to plot a trajectory.

Input:
Aircraft regularly report data such as:

  • longitude
  • latitude
  • aircraft ID
  • callsign
  • ground speed
  • timestamp (indirectly as recorded by the receiving station)

Of interest are also (elementary) airspaces, typically described by a (ground) polygon and minimum and maximum altitude.

Output:
Given the position reports associated to aircraft and the airspaces in the region of interest it would be great to be able to spatially filter the portion of flights intersecting them

Additional information:
Some work on trajectories for aviation is done in R in the {trrrj} package and in Python in the traffic library.

"NAs not allowed in burst" error to build vignettes

Installing with remotes with vignettes throws an error:

> remotes::install_github("mablab/sftrack", build_opts = c("--no-resave-data", "--no-manual"), build_vignettes = TRUE)
Downloading GitHub repo mablab/sftrack@master
✔  checking for file ‘/tmp/Rtmp2iVtLu/remotes17c4ebdc442/mablab-sftrack-6902309/DESCRIPTION’ ...
─  preparing ‘sftrack’:
✔  checking DESCRIPTION meta-information ...
─  installing the package to build vignettes
E  creating vignettes (4.2s)
   Loading required package: sp
   Loading required package: ade4
   Loading required package: adehabitatMA
   Loading required package: CircStats
   Loading required package: MASS
   Loading required package: boot
   Quitting from lines 112-122 (sftrack2_reading.Rmd) 
   Error: processing vignette 'sftrack2_reading.Rmd' failed with diagnostics:
   NAs not allowed in burst
   Execution halted
Error: Failed to install 'sftrack' from GitHub:
  System command 'R' failed, exit status: 1, stdout + stderr (last 10 lines):
E> Loading required package: sp
E> Loading required package: ade4
E> Loading required package: adehabitatMA
E> Loading required package: CircStats
E> Loading required package: MASS
E> Loading required package: boot
E> Quitting from lines 112-122 (sftrack2_reading.Rmd) 
E> Error: processing vignette 'sftrack2_reading.Rmd' failed with diagnostics:
E> NAs not allowed in burst
E> Execution halted
>

Simple install without vignettes runs fine (remotes::install_github("mablab/sftrack")).

Session info:

> sessionInfo()
R version 3.3.3 (2017-03-06)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] ps_1.3.3          fansi_0.4.1       prettyunits_1.1.1 withr_2.2.0      
 [5] crayon_1.3.4      rprojroot_1.3-2   assertthat_0.2.1  R6_2.4.1         
 [9] backports_1.1.8   cli_2.0.2         curl_4.3          remotes_2.1.1    
[13] callr_3.4.3       tools_3.3.3       glue_1.4.1        processx_3.4.3   
[17] pkgbuild_1.1.0   

[Use case] Tidyverse functions for sftrack/sftraj objects

Use case:
Application of tidyverse functions, in analogy to the corresponding methods for sf objects, on sftrack/sftraj objects. A particular use case may be to summarise fixes (points/steps) and related data according to some grouping variable.

Requirements:
Starting from a sftrack/sftraj object, it may be best to provide a new method based on the corresponding sf tidyverse methods (e.g. summarise.sf()) that could handle the spatial part.

In addition, such a method probably should handle multi_burst objects in a special way. I don't have an overview over all tidyverse functions, so I focus on the summarise() topic.

summarise() may have the following effects on the burst variable:

  1. In the simplest case, values are only summarised within burst levels. In this case, the ind_burst for the summarised row could be identical to one of the (identical) input ind_burst objects.
  2. In a more complicated case, values are summarised across burst levels. It would thus be required to provide consistent methods to redefine ind_burst objects (e.g. by (1) assigning a new id to summarised points and (2) using the new grouping variables as new elements of the new ind_burst object). It may also be useful to throw a warning in this case.

I've spotted some potential issues in the current code that may cause problems (I would not call myself too experienced, so I'm not sure if my observations are correct. I was also unsure if this is the right place to post it, but I came across it while trying to apply tidyverse fuctions on sftrack objects):

  1. The class of sftrack objects is currently c("sftrack", "data.frame", "sf"), but for correct method dispatch with the sf package it should be c("sftrack", "sf", "data.frame").
  2. The class of multi_burst objects is currently c("multi_burst"), but for congruence with tidyverse functions, I think one should change it to c("multi_burst", "list").

Input:

  1. sftrack/sftraj object.
  2. ... arguments passed to the tidyverse functions.
  3. Possibly additional arguments on how to handle the burst variable.

Output:
sftrack/sftraj object.

Additional information:
sf tidyverse methods: https://r-spatial.github.io/sf/reference/tidyverse.html

[Use case] Create a `sftraj` object

Use case:
I would find it very useful to have a method to create a sftraj from different other objects (e.g., data.frame and tibble, from SpatialPoints*`` and corresponding sf` objects.

Requirements:
Coordinates, time stamps, CRS.

Input:
A data.frame, tibble, SpatialPoints*, sf. It would be nice, if the user could define a CRS at this point, in case it is not already present. If the starting object has further columns, these should be propagated through. I would like ordering by time stamp to be optional, because the user may have coordinates from several animals (but that might be a point of discussion).

Output:
An sftraj object.

Additional information:
In the amt package there is currently a function amt::make_track that does something similar for data.frames and tibbles. I would very much like to outsource this.

Installation error

In Lucia's computer (Windows):

with remotes::install_github("mablab/sftrack")

error:
c2f78e3/Figures/conceptual-model-full.png: truncated gzip input
tar.exe: Error exit delayed from previous errors.
Error: Failed to install 'sftrack' from GitHub:
Does not appear to be an R package (no DESCRIPTION)

[Use case] Differentiate between point-based and segment-based attributes

Use case:
In, for example adehabitat (other packages take a similar approach I believe), attributes are associated with points (i.e., each row is a GPS point). However, many attributes we are interested in are associated with segments (e.g., consecutive pairs of points). Clearly distinguishing these elements I believe is crucial for a new tracking data model.

Requirements:
The object clearly differentiates between point-based and segment-based attributes, through separate slots/attributes/geometries.

Input:
a dataframe of sftraj object.

Output:
sftraj object
maybe an sftraj can be decomposed into sftraj_points and sftraj_segments (whatever you want to call it)

Additional information:
Making clear the distinction between point-based and segment-based attributes should improve consistency and clarity in subsequent analyses and visualizations. For example, visualizing point-based temperature values vs segment-based speed estimates. Proper treatment of gaps in the data will then also be very important, and would make the data model more generalizable with, for example, human GPS tracking studies.

Travis problem installing gsl on linux

On dev branch travis is now failing on installing gsl, which is probably from adding amt and tracker to suggests. Internet suggest we may need to add some imports so travis can pass. But I havent looked into it thoroughly. This is likely a travis only issue and not a cran check issue as cran checks didnt seem to have this problem for me

Names of sftrack variables (the big 4)

We consider that tracking data can consist of x,y,z,t,id,error dimensions. For the current state of an sftrack object we require:
Coordinates (x,y,z) - Created as an sfc geometry column
A timestamp (t in posix/integer)
A grouping column (id) - currently called 'burs't
And optional error.

Each of these objects as an associated attribute at the sftrack level that describes the associated column name of the variable in the data.frame. Also if the data is supplied as a vector then a default column name is appended to the output data.frame. What should the names of these attributes and their created columns be?

  • sf geometrys are created via st_as_sf and therefore are called 'Geometry' by default. The associated attribute is also sf_column which is created by sf as well. Both of these should likely not change.

  • time column is named reloc_time (standing for relocation time) and the attribute is currently called 'time`, which is pretty generic, I agree with previous comments that the argument should likely be called 'timestamp'. The column name might need to be something less generic as timestamp is a common column name in tracking data.

  • grouping column is currently called burst as well as the attribute, however, this term does not seem to be universally known and not completely describe the purpose of the column. Theres been discussion that the attribute should be called a grouping or group, the column name would have to be something less common.

  • error is called error as an attribute and sftrack_error currently. Both are up for debate.

[Use case] standardized format for observed and modeled animal movement paths

Use case:

This specific use case focusses on the crawl R package for analysis of animal movement. We have long hoped for a standardized format that represents observed input data (e.g. GPS or Argos locations) and the associated error with each observation. The error bit is of critical importance for our application. With a standardized input, we could then develop a standardized output for predicted tracks from the model fit. The key benefit for us as developers is we could reduce the 'data cleaning and troubleshooting' overhead. And, package users would benefit from having an output product that could be used in a variety of, existing or yet to be developed, packages.

Requirements:

The bare minimum requirement would be an ordered (regular or irregular) time series with corresponding coordinates (geographic or projected or simulated space) and a representation of the error associated with each record. Ideally, there would also be support for unique 'animal IDs' and various group-by operations. For the output, we would likely create an extension of the sftraj object to properly capture additional model or prediction metadata and parameters.

Input:

For the crawl package, the idea would be for users to input an sftraj object. For wide scale adoption, the community would need an easy method for creating an sftraj object from typical telemetry observation data sources (usually a csv). The bio-logging community, various repositories (e.g. MoveBank), and manufacturers (e.g. Wildlife Computers, SMRU) might choose to develop options or APIs that allow export of data as an sftraj.

Output:

One option would be for a predicted track from a crawl model fit to be provided as an sftraj object. But, there are a number of model fit parameters that might useful to include in the output. Depending on the structure of the sftraj object, we might need to create a crawl extension/expansion of sftraj. This might be as simple as specifying a set of data frame columns that are included as part of the sftraj.

Additional information:

Convenience functions for sftraj to sf (points) or sf (linestring) (or multipoint, multilinestring) would be helpful. In some cases, telemetry data may record behavior or environmental observations at different time scales/frequencies than the observed locations. In these cases, it would be useful if sftraj supported NULL coordinates so these observations could be stored within the same sftraj structure.

What common step metrics should sftrack calculate.

The step_metrics() attempts to calculate common metrics between successive steps in an sftrack/sftraj. Currently those are:

  • dx
  • dy
  • distance
  • speed
  • absolute angle

What other standardized metrics should be calculated?

The structure and function of the error column

This column/attribute has largely been in a placeholder that we wanted to make sure existed, but wasnt sure what it would look like.

So lets start the discussion, what does an error column need to do? What structure should it look like? What should be required for it?

Is this a post processing column where you create the error using various other packages and its simply a column that stores the error. Or is it a column that you create with as_sftrack and contains all the error variables you can use later (i.e hdop, vdop, etc).

typo

#' @param error (optional) a vector of error information for the movement dataa character string naming the column in `data` where the error information is located

It should be data here.

Bug with integer timestamps: Error in if (tcl == "POSIXct") { : argument is of length zero

If we start with this simple data.frame:

df1 <- data.frame(
    id = rep(1, 10),
    time = 1:10,
    weather = c("clear", "windy", "clear", "windy", "clear", "clear", "rainy", "clear", "cloudy", "cloudy"),
    x = c(0, 1, 1, 1, NA, 2, 3, 1, 2, 2),
    y = c(0, 0, 1, 1, NA, 0, 1, 1, 2, 2)
)

Conversion to sftrack fails on my system:

library("sftrack")
mysftrack <- as_sftrack(data = df1, group = "id", coords = c("x", "y"), time = "time")
## Error in if (tcl == "POSIXct") { : argument is of length zero

The error shows at the very last line (return(ret)), but I'm not exactly sure why. Here is more information in debug mode, right before the error:

Browse[3]> 
debug: return(ret)
Browse[3]> ret
Error in if (tcl == "POSIXct") { : argument is of length zero
Browse[3]> str(ret)
Classes ‘sftrack’, ‘sf’ and 'data.frame':	10 obs. of  7 variables:
 $ id       : num  1 1 1 1 1 1 1 1 1 1
 $ time     : int  1 2 3 4 5 6 7 8 9 10
 $ weather  : Factor w/ 4 levels "clear","cloudy",..: 1 4 1 4 1 1 3 1 2 2
 $ x        : num  0 1 1 1 NA 2 3 1 2 2
 $ y        : num  0 0 1 1 NA 0 1 1 2 2
 $ sft_group:c_grouping object 
List of 10
 $ :List of 1
  ..$ id: chr "1"
  ..- attr(*, "class")= chr "s_group"
  [list output truncated]
 - attr(*, "active_group")= chr "id"
 - attr(*, "sort_index")= Factor w/ 1 level "1": 1 1 1 1 1 1 1 1 1 1
 $ geometry :sfc_POINT of length 10; first list element: Classes 'XY', 'POINT', 'sfg'  num [1:2] 0 0
 - attr(*, "sf_column")= chr "geometry"
 - attr(*, "agr")= Factor w/ 3 levels "constant","aggregate",..: NA NA NA NA NA NA
  ..- attr(*, "names")= chr  "id" "time" "weather" "x" ...
 - attr(*, "group_col")= chr "sft_group"
 - attr(*, "time_col")= chr "time"
 - attr(*, "error_col")= logi NA
Browse[3]> as.data.frame(ret)
   id time weather  x  y sft_group    geometry
1   1    1   clear  0  0   (id: 1) POINT (0 0)
2   1    2   windy  1  0   (id: 1) POINT (1 0)
3   1    3   clear  1  1   (id: 1) POINT (1 1)
4   1    4   windy  1  1   (id: 1) POINT (1 1)
5   1    5   clear NA NA   (id: 1) POINT EMPTY
6   1    6   clear  2  0   (id: 1) POINT (2 0)
7   1    7   rainy  3  1   (id: 1) POINT (3 1)
8   1    8   clear  1  1   (id: 1) POINT (1 1)
9   1    9  cloudy  2  2   (id: 1) POINT (2 2)
10  1   10  cloudy  2  2   (id: 1) POINT (2 2)
Browse[3]> attributes(ret)
$names
[1] "id"        "time"      "weather"   "x"         "y"         "sft_group"
[7] "geometry" 

$row.names
 [1]  1  2  3  4  5  6  7  8  9 10

$class
[1] "sftrack"    "sf"         "data.frame"

$sf_column
[1] "geometry"

$agr
       id      time   weather         x         y sft_group 
     <NA>      <NA>      <NA>      <NA>      <NA>      <NA> 
Levels: constant aggregate identity

$group_col
[1] "sft_group"

$time_col
[1] "time"

$error_col
[1] NA

Session info:

> sessionInfo()
R version 3.3.3 (2017-03-06)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Debian GNU/Linux 9 (stretch)

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] sftrack_0.5

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.5         lubridate_1.7.9    class_7.3-14       crayon_1.3.4      
 [5] sf_0.9-6           dplyr_1.0.0        grid_3.3.3         R6_2.4.1          
 [9] lifecycle_0.2.0    DBI_1.1.0          magrittr_1.5       e1071_1.7-3       
[13] units_0.6-7        pillar_1.4.6       KernSmooth_2.23-15 rlang_0.4.7       
[17] ellipsis_0.3.1     vctrs_0.3.2        generics_0.0.2     tools_3.3.3       
[21] glue_1.4.1         purrr_0.3.4        compiler_3.3.3     pkgconfig_2.0.3   
[25] classInt_0.4-3     tidyselect_1.1.0   tibble_3.0.3      

[Use Case] Major functionality issue: concerting data to `sftrack` breaks functionality of parent class `sf` or `sfc`

I process animal tracking data using sf and just have an extra column for time with entries of type <dttm>. This gives me a ton of functions associated with spatial data, and tidyverse data processing methods.

I am lookeing at sftrack because it would be convenient to have built in track metrics that treat the time as integral to the data much as sf treats the geometry.

However, I've found that it is not worth it because converting objects to sftrack breaks almost all the functions associated with sf objects, including dplyr verbs and mapview.

Because sftrack inherits from sf, I don't see why it shouldn't work with all of these, but it appears that it has something to do with the sftrack idea of "groups". I don't really understand this or how it's advantageous over dplyr groups.

Examples:

> racc_track %>% dplyr::select(height)
Error in UseMethod("group_labels", object = x) : 
  no applicable method for 'group_labels' applied to an object of class "NULL"
> racc_track %>% mapview::mapview()
Error in (function (classes, fdef, mtable)  : 
  unable to find an inherited method for function ‘mapView’ for signature ‘"sftrack"’

[Use case] Transform projection of `sftraj`

Use case:
Transform the coordinate reference system (CRS) of a sftraj.

Requirements:
A sftraj.

Input:
A sftraj with a valid CRS and a EPSG code.

Output:
A sftraj with the CRS transformed to the new ESPG code.

Additional information:
I would expect this to be similar to sf::st_transform.

How should sftrack deal with fractional seconds?

Many tracking devices record in fractional seconds. While some (like gps) do not require that sort of time resolution, some technologies like accelerometers require it at the tenth of a second.

R famously does not treat fractional seconds very well, its format.posix** will round the value with some 'fudge' buffer thats not always well understood. While the fractional second value is intact, the display of it and therefore the conversion of the unit can be easily lost.

https://stackoverflow.com/questions/7726034/how-r-formats-posixct-with-fractional-seconds

What are the best techniques (packages include) that deal with fractional seconds in R?
What is the default display accuracy for sftrack. And should it include special wrapper options to change the display seconds options (options('digits.secs') I believe).

I can post more links, this is a problem ive had on my mind but havent looked into enough

build pkgdown website

Hi, I was trying to install sftrack with its vignettes and the vignettes failed to build (because dependencies on my side).

That got me thinking about whether you could add a pkgdown website which would have the built vignettes as htmls, as well as a neat reference sheet for all the functions.

It's quite painless with pkgdown and helps a ton.

loading failed

Error keeps coming up when loading sftrack after installation:

library(sftrack)
Error: package or namespace load failed for ‘sftrack’ in library.dynam(lib, package, package.lib):
DLL ‘units’ not found: maybe not installed for this architecture?

[Use case] Multi-individual spatial interaction

Use case:
Assuming two individuals with concomitant tracking data. The 'function' would calculate the distance and the azimuth between the relocation of both individuals for each shared timestamp.

Requirements:
spatial coordinates (x,y) as geographic coordinates with projection information
a time (t) as POSIXt object
information that identifies individuals (e.g. animal) for each location

Input:
One sftraj with at least two individual ID with matching timestamps

Output:
two new fields in the sftraj object: distance between the two individual and azimuth between the two individuals

Additional information:

Export as_sftraj object to shapefile

Export as_sftraj object to shapefile using the wt_write() function. Currently there is a GDAL Error 1: Attempt to write non-linestring (POINT) geometry to ARC type shapefile.

[Use case] Adding missing data

Use case:
GPS data is typically full of missing data, i.e. records with no coordinates because the device could not get satellite signal and gave up. Raw data typically comes with rows including all other information (including time), but empty longitude and latitude. sftraj objects should be able to keep them on creation, or be able to add them if they were not initially present in the data (i.e. add those missing attempts back in the data).

Requirements:

  • sftraj objects should be able to include points with no coordinates (NULL); and build steps with these NULL points
  • adding missing data should not change the data in any other respect; sftraj objects should be able to remove those NAs and get the initial data back in its exact initial state.

Input:

  • If the initial data already has missing data, a data.frame with rows with 0-coordinates.
  • If the initial data does not have missing data, a sftraj with gaps in the data.

Output:
In both cases, a sftraj object with missing data included.

Additional information:
I guess for now, the algorithm to add missing records is beyond the scope of the package (see adehabitatLT::setNA).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.