sft_timestamp
One requirement for a movement object is it must have a measurement of time. This unit can be sequential numbers dictating the order in which points were taken, or actual time. For the sake of sftrack
, we allow either measurement of time. Time objects are stored in a column as an sft_timestamp
class. This class is at the column level and is a collection of time measurements for a set of spatial points or steps.
## 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
time <- make_timestamp(raccoons$timestamp)
time[1:10]
## [1] "2019-01-18 19:02:30 EST" "2019-01-18 20:02:30 EST"
## [3] "2019-01-18 21:02:30 EST" "2019-01-18 22:02:30 EST"
## [5] "2019-01-18 23:02:30 EST" "2019-01-19 00:02:30 EST"
## [7] "2019-01-19 01:02:30 EST" "2019-01-19 02:02:04 EST"
## [9] "2019-01-19 03:02:30 EST" "2019-01-19 12:02:30 EST"
When time is represented by a vector with one timestamp for each point, the time class acts just like a POSIXct or numeric object (and actually supersedes both).
time[1:10] + 60
## [1] "2019-01-18 19:03:30 EST" "2019-01-18 20:03:30 EST"
## [3] "2019-01-18 21:03:30 EST" "2019-01-18 22:03:30 EST"
## [5] "2019-01-18 23:03:30 EST" "2019-01-19 00:03:30 EST"
## [7] "2019-01-19 01:03:30 EST" "2019-01-19 02:03:04 EST"
## [9] "2019-01-19 03:03:30 EST" "2019-01-19 12:03:30 EST"
class(time)
## [1] "sft_timestamp" "POSIXct" "POSIXt"
The only difference is it retains a few extra attributes at the column level for ease of calculating upon the entire list. These include retaining the timezone information and a descriptor if the list contains POSIX
or numeric
measurement of time. These attributes are only used by sftrack
functions. The real tzone
attribute reamains in each row level object.
attributes(time)
## $class
## [1] "sft_timestamp" "POSIXct" "POSIXt"
##
## $tzone
## [1] "EST5EDT"
##
## $type
## [1] "POSIX"
attributes(time[[1]])
## $class
## [1] "sft_timestamp" "POSIXct" "POSIXt"
##
## $tzone
## [1] "EST5EDT"
Timestamp classes are automatically created in sftrack
and sftraj
objects, though they differ in the structure of time. An sftrack
object only requires the start time (\(t_1\)) and thus stores only one measurement of time similar as seen above.
racc_track
## sftrack (*locations*) with 445 features and 10 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## timestamps: "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_group geometry
## 1 (id: TTP-058, month: 1) POINT EMPTY
## 2 (id: TTP-058, month: 1) POINT (-80.27906 26.06945)
## 3 (id: TTP-058, month: 1) POINT EMPTY
## 4 (id: TTP-058, month: 1) POINT EMPTY
## 5 (id: TTP-058, month: 1) POINT (-80.27431 26.06769)
## 6 (id: TTP-058, month: 1) POINT (-80.2793 26.06867)
Trajectories, require a start and end time for each step. This requires a multi-dimensional time object.
racc_traj
## sftraj (*steps*) with 445 features and 10 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## 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 sft_group geometry
## 1 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 2 7 6.2 3.2 2D (id: TTP-058, month: 1) POINT (-80.27906 26.06945)
## 3 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 4 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 5 858 5.1 3.2 2D (id: TTP-058, month: 1) LINESTRING (-80.27431 26.06...
## 6 350 1.9 3.2 3D (id: TTP-058, month: 1) LINESTRING (-80.2793 26.068...
Each row is a time interval that is independent of the other rows. So deleting a step (for instance with the same start time as a previous entries end time) does not affect the previous step in any way.
racc_traj[-2, ]
## sftraj (*steps*) with 444 features and 10 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## 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)
## 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)
## 7 TTP-058 26.06962 -80.27908 (2019-01-19 01:02:30 --> 2019-01-19 02:02:04)
## height hdop vdop fix sft_group geometry
## 1 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 3 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 4 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 5 858 5.1 3.2 2D (id: TTP-058, month: 1) LINESTRING (-80.27431 26.06...
## 6 350 1.9 3.2 3D (id: TTP-058, month: 1) LINESTRING (-80.2793 26.068...
## 7 11 2.3 4.5 3D (id: TTP-058, month: 1) LINESTRING (-80.27908 26.06...
t1
and t2
t1
is a basic function to grab the starting point of any sftrack
or sftraj
object, as well as sft_timestamp
classes directly. In most cases this is simply lapply(timestamp, function(x) x[[1]])
.
# sftrack
t1(racc_track[1:5, ])
## [1] "2019-01-18 19:02:30 EST" "2019-01-18 20:02:30 EST"
## [3] "2019-01-18 21:02:30 EST" "2019-01-18 22:02:30 EST"
## [5] "2019-01-18 23:02:30 EST"
# sftraj
t1(racc_traj[1:5, ])
## [1] "2019-01-18 19:02:30 EST" "2019-01-18 20:02:30 EST"
## [3] "2019-01-18 21:02:30 EST" "2019-01-18 22:02:30 EST"
## [5] "2019-01-18 23:02:30 EST"
# sft_timestamp
t1(racc_traj$timestamp[1:5])
## [1] "2019-01-18 19:02:30 EST" "2019-01-18 20:02:30 EST"
## [3] "2019-01-18 21:02:30 EST" "2019-01-18 22:02:30 EST"
## [5] "2019-01-18 23:02:30 EST"
t2
is a more complex function. t2
is inherently easy in an sftraj
where the true end point is stored in the timestamp, and in this case t2
is thus simply lapply(timestamp, function(x) x[[2]])
.
t2(racc_traj[1:5,])
## [1] "2019-01-18 20:02:30 EST" "2019-01-18 21:02:30 EST"
## [3] "2019-01-18 22:02:30 EST" "2019-01-18 23:02:30 EST"
## [5] "2019-01-19 00:02:30 EST"
sftrack
, POSIXt
, or numeric
vectors do not obviously have a \(t_2\). In these cases, because it is useful internally, and possibly to the user, t2
computes a lag of “time1” (i.e. takes the next record). When supplied with a sftrack
the grouping is used to compute a more accurate \(t_2\) with the grouping considered. When a single vector is supplied with either sft_timestamp
, POSIX
, or numeric
a simple lag of 1 is computed with time.
t2(racc_track[1:5, ])
## [1] "2019-01-18 20:02:30 EST" "2019-01-18 21:02:30 EST"
## [3] "2019-01-18 22:02:30 EST" "2019-01-18 23:02:30 EST"
## [5] NA
## [1] "2021-07-01 16:00:07 CEST" "2021-07-01 16:00:08 CEST"
## [3] "2021-07-01 16:00:09 CEST" "2021-07-01 16:00:10 CEST"
## [5] "2021-07-01 16:00:11 CEST" "2021-07-01 16:00:12 CEST"
## [7] "2021-07-01 16:00:13 CEST" "2021-07-01 16:00:14 CEST"
## [9] "2021-07-01 16:00:15 CEST" NA
t2(1:10)
## [1] 2 3 4 5 6 7 8 9 10 NA
If you’d like to calculate \(t_2\) with grouping considered on these 1 dimensional vectors, you can use t2_by_group
, which requires \(t_1\) and the grouping.
grouping <- make_c_grouping(list(id = rep(1:2, 5)))
t2 <- t2_by_group(1:10, grouping)
data.frame(t1 = 1:10, t2 = t2, group = grouping)
## t1 t2 id
## 1 1 3 (id: 1)
## 2 2 4 (id: 2)
## 3 3 5 (id: 1)
## 4 4 6 (id: 2)
## 5 5 7 (id: 1)
## 6 6 8 (id: 2)
## 7 7 9 (id: 1)
## 8 8 10 (id: 2)
## 9 9 NA (id: 1)
## 10 10 NA (id: 2)
sftraj
objectWhile a step model of a sftraj
generally assumes that both \(t_1\) and \(t_2\) of a step are independent of other steps, occasionally \(t_2\) may need to be recalculated in an sftraj
(for instance because of outliers or subsetting). In order to do this you can use time_recalc()
. This function only works on sftraj
objects:
sub_traj <- racc_traj[-2, ]
(new_traj <- time_recalc(sub_traj))
## sftraj (*steps*) with 444 features and 10 fields
## geometry: "geometry" (XY, CRS: WGS 84)
## 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 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)
## 7 TTP-058 26.06962 -80.27908 (2019-01-19 01:02:30 --> 2019-01-19 02:02:04)
## height hdop vdop fix sft_group geometry
## 1 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 3 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 4 NA 0.0 0.0 NO (id: TTP-058, month: 1) POINT EMPTY
## 5 858 5.1 3.2 2D (id: TTP-058, month: 1) LINESTRING (-80.27431 26.06...
## 6 350 1.9 3.2 3D (id: TTP-058, month: 1) LINESTRING (-80.2793 26.068...
## 7 11 2.3 4.5 3D (id: TTP-058, month: 1) LINESTRING (-80.27908 26.06...
This does not recalculate the geometries, that must be done separately with step_recalc
.