Creating sftrack objects is relatively straight forward and can be read in a variety of ways including as a standard data.frame
, sf
object, or ltraj
object (from adehabitatLT
).
To create sftrack
objects data we use the as_sftrack()
(track) or as_sftraj()
(trajectory) function, depending on your desired output. Both have the same arguments but differ in the way the geometry field is calculated.
as_sftrack()/as_sftraj
accepts 2 kinds of raw data for each of the 4 required parts. Either a vector/list representing the data where length = nrow(data), or the column name where the data exists. For any sftrack
component you can input either vector data or the column name for any variable, and can mix types between arguments.
Vector inputs to as_sftrack
generally involve feeding as_sftrack the data itself where length(vector) == nrow(data). Or a list where each component adheres to this rule. If using entirely vector inputs for grouping, geometry, time, and error then data
is not required.
data.frame inputs on the other hand are simply character vectors describing the column name in data
where the information is found.
data - is a data.frame containing your data. Data is optional if all inputs are done in vector mode where the appropriate vectors are given for geometry, grouping, and time. If inputting vector mode, sftrack creates column names sft_group
, sft_timestamp
, and sft_error
in data frame. Names can be manually changed using group_name
, time_name
, and error_name
and changing overwrite_names
to FALSE will write over the data if the column already exists in data
.
group (required) - a list with named vectors to group the sftrack. One group must be named id
, but otherwise can be infinite number of grouping variables. Or a vector naming the column names for each grouping categories. If only one variable is given then that vector is assumed to be the id column.
coords (required) - The x,y,z coordinates to calculate geometries via sf
. Accepts either a vector of c(x,y,z)
describing which column the coordinates can be found, or a list(x=, y=, z=) with vectors for each coordinate. z is optional. NAs are allowed, alhough NAs must exist through the entire row otherwise an error is thrown. This is the same argument from sf
functions and feeds into st_as_sf()
internally.
time (required) - Time information in either POSIXct
or as an integer
. Accepts either a vector of time, or the column name found in data
. The outputted object will be sorted by the time column.
error - Error information for the associated xyz point. Accepts either a vector of the error, or the column name found in data
. If not given, default = NA.
crs - the coordinate references system/projection of the data, as implemented by rgdal. see ?rgdal::CRS-class
for more information. If none is supplied crs is set as NA and can be set later using sf::st_crs()
from sf
.
active_group (required) - This is a vector containing what groups are ‘active’. Meaning calculations and graphing will use these groupings. If no value is supplied it defaults to all grouping variables. Can change active_group later using active_group() <- 'myvalue'
.
In the case of vector inputs, the vectors are cbinded to data
if data is supplied. Sftrack returns an error if the column name already exists in the data.frame and overwrite_names
remains FALSE. Default column names are: group = ‘sft_group’, time = ‘sft_timestamp’, error = ‘sft_error’. Names can be overwitten using overwrite_names = TRUE
. At present Geometry defaults as ‘Geometry’ and at present can be changed later via sf
but not via sftrack
as we make a new sf object when we make an sftrack object.
## 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
## Coordinates and projection
coords <- raccoons[, c("longitude", "latitude")]
crs <- "+init=epsg:4326"
## Grouping
group <- list(id = raccoons$animal_id,
month = as.POSIXlt(raccoons$timestamp)$mon + 1)
active_group <- c("id", "month")
## Time
time <- raccoons$timestamp
## Error
error <- raccoons$fix
racc_track <- as_sftrack(data = raccoons, coords = coords, group = group,
active_group = active_group, time = time,
crs = crs, error = error)
## Warning in CPL_crs_from_input(x): GDAL Message 1: +init=epsg:XXXX syntax is
## deprecated. It might return a CRS with a non-EPSG compliant axis order.
racc_track
## sftrack (*locations*) with 445 features and 12 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## timestamps: "sft_timestamp" (integer)
## groupings: "sft_group" (*id*, *month*)
## -------------------------------
## 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_timestamp sft_error sft_group
## 1 2019-01-18 19:02:30 NO (id: TTP-058, month: 1)
## 2 2019-01-18 20:02:30 2D (id: TTP-058, month: 1)
## 3 2019-01-18 21:02:30 NO (id: TTP-058, month: 1)
## 4 2019-01-18 22:02:30 NO (id: TTP-058, month: 1)
## 5 2019-01-18 23:02:30 2D (id: TTP-058, month: 1)
## 6 2019-01-19 00:02:30 3D (id: TTP-058, month: 1)
## geometry
## 1 POINT EMPTY
## 2 POINT (-80.27906 26.06945)
## 3 POINT EMPTY
## 4 POINT EMPTY
## 5 POINT (-80.27431 26.06769)
## 6 POINT (-80.2793 26.06867)
As you can see in this case the data is not overwritten, but extra columns added with the correct data.
data.frame
inputsData.frame inputs generally describe the columns that represent the variables in data
. If the columns are not found in data
, an error is returned.
raccoons$month <- as.POSIXlt(raccoons$timestamp)$mon + 1
coords <- c("longitude", "latitude")
group <- c(id = "animal_id", month = "month")
time <- "timestamp"
error <- "fix"
racc_traj <- as_sftraj(data = raccoons, coords = coords, group = group,
time = time, error = error)
racc_traj
## sftraj (*steps*) with 445 features and 11 fields
## geometry: "geometry" (XY, CRS: NA)
## timestamps: "timestamp" (integer)
## groupings: "sft_group" (*id*, *month*)
## -------------------------------
## animal_id latitude longitude timestamp
## 1 TTP-058 NA NA (2019-01-18 19:02:30 --> 2019-01-18 20:02:30)
## 2 TTP-058 26.06945 -80.27906 (2019-01-18 20:02:30 --> 2019-01-18 21:02:30)
## 3 TTP-058 NA NA (2019-01-18 21:02:30 --> 2019-01-18 22:02:30)
## 4 TTP-058 NA NA (2019-01-18 22:02:30 --> 2019-01-18 23:02:30)
## 5 TTP-058 26.06769 -80.27431 (2019-01-18 23:02:30 --> 2019-01-19 00:02:30)
## 6 TTP-058 26.06867 -80.27930 (2019-01-19 00:02:30 --> 2019-01-19 01:02:30)
## height hdop vdop fix month sft_group
## 1 NA 0.0 0.0 NO 1 (id: TTP-058, month: 1)
## 2 7 6.2 3.2 2D 1 (id: TTP-058, month: 1)
## 3 NA 0.0 0.0 NO 1 (id: TTP-058, month: 1)
## 4 NA 0.0 0.0 NO 1 (id: TTP-058, month: 1)
## 5 858 5.1 3.2 2D 1 (id: TTP-058, month: 1)
## 6 350 1.9 3.2 3D 1 (id: TTP-058, month: 1)
## geometry
## 1 POINT EMPTY
## 2 POINT (-80.27906 26.06945)
## 3 POINT EMPTY
## 4 POINT EMPTY
## 5 LINESTRING (-80.27431 26.06...
## 6 LINESTRING (-80.2793 26.068...
as_sftrack()
and as_sftraj()
also accept other data types, but the arguments for each differ depending on the class they’re converting from. They currently accepts, sf
, ltraj
(from adehabitatLT
), trackeRdata
(from trackeR
), and track_xyt
(from amt
).
adehabitat::ltraj
To read in an ltraj
object all you need is an actual ltraj
object created in adehabitatLT
. All relevant information is taken from the object. Bursts as defined in an ltraj
are slightly different than sftrack
’s groupings, so it assumes the ltraj
burst is the id
field of the sftrack
grouping object.
library("adehabitatLT")
racc_ltraj <- as.ltraj(xy = raccoons[,c("longitude", "latitude")],
date = raccoons$timestamp,
id = raccoons$animal_id,
infolocs = raccoons[,1:6])
as_sftrack(racc_ltraj)
## sftrack (*locations*) with 445 features and 12 fields
## geometry: "geometry" (XY, CRS: NA)
## timestamps: "sft_timestamp" (integer)
## groupings: "sft_group" (*id*)
## -------------------------------
## x y burst sft_timestamp animal_id latitude longitude
## 223 NA NA TTP-041 2019-01-18 19:02:30 TTP-041 NA NA
## 224 -80.27933 26.07096 TTP-041 2019-01-18 20:02:30 TTP-041 26.07096 -80.27933
## 225 -80.27932 26.07025 TTP-041 2019-01-18 21:02:22 TTP-041 26.07025 -80.27932
## 226 -80.27936 26.07071 TTP-041 2019-01-18 22:02:13 TTP-041 26.07071 -80.27936
## 227 -80.27924 26.07097 TTP-041 2019-01-18 23:02:30 TTP-041 26.07097 -80.27924
## 228 -80.27942 26.07072 TTP-041 2019-01-19 00:02:09 TTP-041 26.07072 -80.27942
## timestamp height hdop sft_group geometry
## 223 2019-01-18 19:02:30 NA 0.0 (id: TTP-041) POINT EMPTY
## 224 2019-01-18 20:02:30 7 7.0 (id: TTP-041) POINT (-80.27933 26.07096)
## 225 2019-01-18 21:02:22 7 3.9 (id: TTP-041) POINT (-80.27932 26.07025)
## 226 2019-01-18 22:02:13 1 4.7 (id: TTP-041) POINT (-80.27936 26.07071)
## 227 2019-01-18 23:02:30 23 4.5 (id: TTP-041) POINT (-80.27924 26.07097)
## 228 2019-01-19 00:02:09 22 2.3 (id: TTP-041) POINT (-80.27942 26.07072)
sf
objects are handled similarly as data.frame
inputs except you do not need to input any information about the coordinates or projection. Grouping and time are still required. The sf
GEOMETRY must be in an sfc_POINT
column.
## Linking to GEOS 3.9.0, GDAL 3.2.2, PROJ 7.2.1
racc_sf <- st_as_sf(raccoons, coords = c("longitude","latitude"),
crs = "+init=epsg:4326", remove = FALSE,
na.fail = FALSE)
group <- c(id = "animal_id")
time_col <- "timestamp"
racc_sf
## Simple feature collection with 445 features and 9 fields
## Geometry type: POINT
## Dimension: XY
## Bounding box: xmin: -80.28149 ymin: 26.06761 xmax: -80.27046 ymax: 26.07706
## Geodetic CRS: WGS 84
## First 10 features:
## animal_id latitude longitude timestamp height hdop vdop fix month
## 1 TTP-058 NA NA 2019-01-18 19:02:30 NA 0.0 0.0 NO 1
## 2 TTP-058 26.06945 -80.27906 2019-01-18 20:02:30 7 6.2 3.2 2D 1
## 3 TTP-058 NA NA 2019-01-18 21:02:30 NA 0.0 0.0 NO 1
## 4 TTP-058 NA NA 2019-01-18 22:02:30 NA 0.0 0.0 NO 1
## 5 TTP-058 26.06769 -80.27431 2019-01-18 23:02:30 858 5.1 3.2 2D 1
## 6 TTP-058 26.06867 -80.27930 2019-01-19 00:02:30 350 1.9 3.2 3D 1
## 7 TTP-058 26.06962 -80.27908 2019-01-19 01:02:30 11 2.3 4.5 3D 1
## 8 TTP-058 26.06963 -80.27902 2019-01-19 02:02:04 9 2.7 3.9 3D 1
## 9 TTP-058 NA NA 2019-01-19 03:02:30 NA 0.0 0.0 NO 1
## 10 TTP-058 26.06982 -80.27900 2019-01-19 12:02:30 NA 2.0 3.3 3D 1
## geometry
## 1 POINT EMPTY
## 2 POINT (-80.27906 26.06945)
## 3 POINT EMPTY
## 4 POINT EMPTY
## 5 POINT (-80.27431 26.06769)
## 6 POINT (-80.2793 26.06867)
## 7 POINT (-80.27908 26.06962)
## 8 POINT (-80.27902 26.06963)
## 9 POINT EMPTY
## 10 POINT (-80.279 26.06982)
as_sftraj(racc_sf, group = group, time= time_col)
## sftraj (*steps*) with 445 features and 11 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## timestamps: "timestamp" (integer)
## groupings: "sft_group" (*id*)
## -------------------------------
## animal_id latitude longitude timestamp
## 1 TTP-058 NA NA (2019-01-18 19:02:30 --> 2019-01-18 20:02:30)
## 2 TTP-058 26.06945 -80.27906 (2019-01-18 20:02:30 --> 2019-01-18 21:02:30)
## 3 TTP-058 NA NA (2019-01-18 21:02:30 --> 2019-01-18 22:02:30)
## 4 TTP-058 NA NA (2019-01-18 22:02:30 --> 2019-01-18 23:02:30)
## 5 TTP-058 26.06769 -80.27431 (2019-01-18 23:02:30 --> 2019-01-19 00:02:30)
## 6 TTP-058 26.06867 -80.27930 (2019-01-19 00:02:30 --> 2019-01-19 01:02:30)
## height hdop vdop fix month sft_group geometry
## 1 NA 0.0 0.0 NO 1 (id: TTP-058) POINT EMPTY
## 2 7 6.2 3.2 2D 1 (id: TTP-058) POINT (-80.27906 26.06945)
## 3 NA 0.0 0.0 NO 1 (id: TTP-058) POINT EMPTY
## 4 NA 0.0 0.0 NO 1 (id: TTP-058) POINT EMPTY
## 5 858 5.1 3.2 2D 1 (id: TTP-058) LINESTRING (-80.27431 26.06...
## 6 350 1.9 3.2 3D 1 (id: TTP-058) LINESTRING (-80.2793 26.068...
Additionally as_sftrack
and as_sftraj
can convert back and forth between classes with no loss in information.
## Convert between types
new_sftrack <- as_sftrack(racc_traj)
new_sftraj <- as_sftraj(racc_track)
identical(racc_traj, new_sftraj)
## [1] FALSE
identical(racc_track, new_sftrack)
## [1] FALSE
A common issue with movement data is when duplicated gps time stamps are logged for a sensor. When this happens it can be impossible for sftrack
to know which point to use. For this reason, sftrack returns an error if any grouping
+ time
combinations are duplicated.
raccoons$timestamp[1] <- raccoons$timestamp[2]
try(as_sftrack(data = raccoons, coords = coords, group = group, time = time, error = error))
## Error in dup_timestamp(time = data[[time_col]], x = group) :
## groups: TTP-058 have duplicated time stamps
To help determine which rows are duplicated you can use the which_duplicated()
function to check your inputs. After which you can delete the superfluous rows and try again:
which_duplicated(data = raccoons , group = group, time = time)
## group time which_row
## 1 TTP-058 2019-01-18 20:02:30 1
## 2 TTP-058 2019-01-18 20:02:30 2
raccoons <- raccoons[-2, ]
coords <- raccoons[, c("longitude", "latitude")]
crs <- "+init=epsg:4326"
group <- list(id = raccoons$animal_id,
month = as.POSIXlt(raccoons$timestamp)$mon + 1)
active_group <- c("id", "month")
time <- raccoons$timestamp
error <- raccoons$fix
racc_track <- as_sftrack(data = raccoons, coords = coords, group = group,
active_group = active_group, time = time,
crs = crs, error = error)