library(trackdf)
data("tracks")
Under the hood, a track table is just a simple data frame of class data.frame
,
tibble
or data.table
with a few extra bells and whistles. This means that you can manipulate
a track table same way you would a data frame of any of these three
classes.
To create a track table based on data.frame
, do:
<- track(x = tracks$x, y = tracks$y, t = tracks$t, id = tracks$id,
t_df proj = "+proj=longlat", tz = "Africa/Windhoek", table = "df")
head(t_df)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 15.76468 -22.37957
## 2 1 2015-09-10 07:00:01 15.76468 -22.37957
## 3 1 2015-09-10 07:00:04 15.76468 -22.37958
## 4 1 2015-09-10 07:00:05 15.76468 -22.37958
## 5 1 2015-09-10 07:00:08 15.76467 -22.37959
## 6 1 2015-09-10 07:00:09 15.76467 -22.37959
To create a track table based on tibble
, do:
<- track(x = tracks$x, y = tracks$y, t = tracks$t, id = tracks$id,
t_tbl proj = "+proj=longlat", tz = "Africa/Windhoek", table = "tbl")
t_tbl
## Track table [7194 observations]
## Number of tracks: 2
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: tibble
## # A tibble: 7,194 × 4
## id t x y
## <chr> <dttm> <dbl> <dbl>
## 1 1 2015-09-10 07:00:00 15.8 -22.4
## 2 1 2015-09-10 07:00:01 15.8 -22.4
## 3 1 2015-09-10 07:00:04 15.8 -22.4
## 4 1 2015-09-10 07:00:05 15.8 -22.4
## 5 1 2015-09-10 07:00:08 15.8 -22.4
## 6 1 2015-09-10 07:00:09 15.8 -22.4
## 7 1 2015-09-10 07:00:10 15.8 -22.4
## 8 1 2015-09-10 07:00:11 15.8 -22.4
## 9 1 2015-09-10 07:00:12 15.8 -22.4
## 10 1 2015-09-10 07:00:13 15.8 -22.4
## # … with 7,184 more rows
To create a track table based on data.table
, do:
<- track(x = tracks$x, y = tracks$y, t = tracks$t, id = tracks$id,
t_dt proj = "+proj=longlat", tz = "Africa/Windhoek", table = "dt")
t_dt
## Track table [7194 observations]
## Number of tracks: 2
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data table
## id t x y
## 1: 1 2015-09-10 07:00:00 15.76468 -22.37957
## 2: 1 2015-09-10 07:00:01 15.76468 -22.37957
## 3: 1 2015-09-10 07:00:04 15.76468 -22.37958
## 4: 1 2015-09-10 07:00:05 15.76468 -22.37958
## 5: 1 2015-09-10 07:00:08 15.76467 -22.37959
## ---
## 7190: 2 2015-09-10 07:59:55 15.76246 -22.37763
## 7191: 2 2015-09-10 07:59:56 15.76245 -22.37763
## 7192: 2 2015-09-10 07:59:57 15.76244 -22.37762
## 7193: 2 2015-09-10 07:59:58 15.76243 -22.37762
## 7194: 2 2015-09-10 07:59:59 15.76243 -22.37761
You can check whether an object is a track table as follows:
is_track(t_df)
## [1] TRUE
is_track(t_tbl)
## [1] TRUE
is_track(t_dt)
## [1] TRUE
You can check whether a track table contains geographic coordinates or not as follows:
is_geo(t_df)
## [1] TRUE
is_geo(t_tbl)
## [1] TRUE
is_geo(t_dt)
## [1] TRUE
You can access the different parts (rows, columns, elements) of a track table as follows:
head(t_df$id)
## [1] "1" "1" "1" "1" "1" "1"
head(t_tbl$id)
## [1] "1" "1" "1" "1" "1" "1"
head(t_dt$id)
## [1] "1" "1" "1" "1" "1" "1"
head(t_df[["t"]])
## [1] "2015-09-10 07:00:00 CAT" "2015-09-10 07:00:01 CAT"
## [3] "2015-09-10 07:00:04 CAT" "2015-09-10 07:00:05 CAT"
## [5] "2015-09-10 07:00:08 CAT" "2015-09-10 07:00:09 CAT"
head(t_tbl[["t"]])
## [1] "2015-09-10 07:00:00 CAT" "2015-09-10 07:00:01 CAT"
## [3] "2015-09-10 07:00:04 CAT" "2015-09-10 07:00:05 CAT"
## [5] "2015-09-10 07:00:08 CAT" "2015-09-10 07:00:09 CAT"
head(t_dt[["t"]])
## [1] "2015-09-10 07:00:00 CAT" "2015-09-10 07:00:01 CAT"
## [3] "2015-09-10 07:00:04 CAT" "2015-09-10 07:00:05 CAT"
## [5] "2015-09-10 07:00:08 CAT" "2015-09-10 07:00:09 CAT"
head(t_df[1])
## id
## 1 1
## 2 1
## 3 1
## 4 1
## 5 1
## 6 1
1] t_tbl[
## # A tibble: 7,194 × 1
## id
## <chr>
## 1 1
## 2 1
## 3 1
## 4 1
## 5 1
## 6 1
## 7 1
## 8 1
## 9 1
## 10 1
## # … with 7,184 more rows
1] t_dt[
## Track table [1 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data table
## id t x y
## 1: 1 2015-09-10 07:00:00 15.76468 -22.37957
1, ] t_df[
## Track table [1 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 15.76468 -22.37957
1, ] t_tbl[
## Track table [1 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: tibble
## # A tibble: 1 × 4
## id t x y
## <chr> <dttm> <dbl> <dbl>
## 1 1 2015-09-10 07:00:00 15.8 -22.4
1, ] t_dt[
## Track table [1 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data table
## id t x y
## 1: 1 2015-09-10 07:00:00 15.76468 -22.37957
1, 1] t_df[
## [1] "1"
1, 1] t_tbl[
## # A tibble: 1 × 1
## id
## <chr>
## 1 1
1, 1] t_dt[
## id
## 1: 1
Note that the results varies depending on the underlying data frame class.
By combining the commands above with the <-
operator,
you can easily modify the content of a track table. For example:
$id[t_df$id == "1"] <- "0"
t_dfhead(t_df)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 0 2015-09-10 07:00:00 15.76468 -22.37957
## 2 0 2015-09-10 07:00:01 15.76468 -22.37957
## 3 0 2015-09-10 07:00:04 15.76468 -22.37958
## 4 0 2015-09-10 07:00:05 15.76468 -22.37958
## 5 0 2015-09-10 07:00:08 15.76467 -22.37959
## 6 0 2015-09-10 07:00:09 15.76467 -22.37959
1] == "0", 1] <- "1"
t_df[t_df[, head(t_df)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 15.76468 -22.37957
## 2 1 2015-09-10 07:00:01 15.76468 -22.37957
## 3 1 2015-09-10 07:00:04 15.76468 -22.37958
## 4 1 2015-09-10 07:00:05 15.76468 -22.37958
## 5 1 2015-09-10 07:00:08 15.76467 -22.37959
## 6 1 2015-09-10 07:00:09 15.76467 -22.37959
You can access the projection of a track table as follows.
projection(t_df)
## Coordinate Reference System:
## User input: +proj=longlat
## wkt:
## GEOGCRS["unknown",
## DATUM["World Geodetic System 1984",
## ELLIPSOID["WGS 84",6378137,298.257223563,
## LENGTHUNIT["metre",1]],
## ID["EPSG",6326]],
## PRIMEM["Greenwich",0,
## ANGLEUNIT["degree",0.0174532925199433],
## ID["EPSG",8901]],
## CS[ellipsoidal,2],
## AXIS["longitude",east,
## ORDER[1],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]],
## AXIS["latitude",north,
## ORDER[2],
## ANGLEUNIT["degree",0.0174532925199433,
## ID["EPSG",9122]]]]
You can modify in place the projection of a track table as follows. This will automatically convert the coordinates in the appropriate projection system.
projection(t_df) <- "+proj=somerc +lat_0=46.9524056 +lon_0=7.43958333 +ellps=bessel +x_0=2600000 +y_0=1200000 +towgs84=674.374,15.056,405.346 +units=m +k_0=1 +no_defs"
head(t_df)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=somerc +lat_0=46.9524056 +lon_0=7.43958333 +ellps=bessel +x_0=2600000 +y_0=1200000 +towgs84=674.374,15.056,405.346 +units=m +k_0=1 +no_defs
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 4927487 -9217299
## 2 1 2015-09-10 07:00:01 4927487 -9217299
## 3 1 2015-09-10 07:00:04 4927487 -9217301
## 4 1 2015-09-10 07:00:05 4927487 -9217302
## 5 1 2015-09-10 07:00:08 4927486 -9217304
## 6 1 2015-09-10 07:00:09 4927485 -9217305
projection(t_df) <- "+proj=longlat"
head(t_df)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 15.76468 -22.37957
## 2 1 2015-09-10 07:00:01 15.76468 -22.37957
## 3 1 2015-09-10 07:00:04 15.76468 -22.37958
## 4 1 2015-09-10 07:00:05 15.76468 -22.37958
## 5 1 2015-09-10 07:00:08 15.76467 -22.37959
## 6 1 2015-09-10 07:00:09 15.76467 -22.37959
If you prefer not to modify the original object, you can create a new one with the new projection as follows.
<- project(t_df, "+proj=somerc +lat_0=46.9524056 +lon_0=7.43958333 +ellps=bessel +x_0=2600000 +y_0=1200000 +towgs84=674.374,15.056,405.346 +units=m +k_0=1 +no_defs")
t_df_new_proj
head(t_df_new_proj)
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=somerc +lat_0=46.9524056 +lon_0=7.43958333 +ellps=bessel +x_0=2600000 +y_0=1200000 +towgs84=674.374,15.056,405.346 +units=m +k_0=1 +no_defs
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 4927487 -9217299
## 2 1 2015-09-10 07:00:01 4927487 -9217299
## 3 1 2015-09-10 07:00:04 4927487 -9217301
## 4 1 2015-09-10 07:00:05 4927487 -9217302
## 5 1 2015-09-10 07:00:08 4927486 -9217304
## 6 1 2015-09-10 07:00:09 4927485 -9217305
Track tables are compatible with the functions from the tidyverse (with one notable
exception, see below). For instance, you can use all the dplyr
verbs to
filter, mutate, group, etc., a track table, the same way you would do
with a tibble
or a data.frame
.
if (requireNamespace("dplyr", quietly = TRUE)) {
library(dplyr)
%>%
t_df filter(., t < as.POSIXct("2015-09-10 07:01:00", tz = "Africa/Windhoek")) %>%
head(.)
}
## Track table [6 observations]
## Number of tracks: 1
## Dimensions: 2D
## Geographic: TRUE
## Projection: +proj=longlat
## Table class: data frame
## id t x y
## 1 1 2015-09-10 07:00:00 15.76468 -22.37957
## 2 1 2015-09-10 07:00:01 15.76468 -22.37957
## 3 1 2015-09-10 07:00:04 15.76468 -22.37958
## 4 1 2015-09-10 07:00:05 15.76468 -22.37958
## 5 1 2015-09-10 07:00:08 15.76467 -22.37959
## 6 1 2015-09-10 07:00:09 15.76467 -22.37959
if (requireNamespace("dplyr", quietly = TRUE)) {
library(dplyr)
%>%
t_df group_by(., id) %>%
summarize(., x = mean(x),
y = mean(y))
}
## # A tibble: 2 × 3
## id x y
## <chr> <dbl> <dbl>
## 1 1 15.8 -22.4
## 2 2 15.8 -22.4
bind_rows
is a notable exception to the rule above.
Indeed, when combining two data frames, only the attributes of the first
data frame passed to bind_rows
are retained in the output
data frame. As a result, combining with bind_rows
two track
tables with different projections will ignore the projection of the
second track table and assume it is the same as the first one. To avoid
this issue, trackdf
provides a special version of
bind_rows
called bind_tracks
that checks first
that the dimensions, geographic status, and projections of the input
track tables are compatible with each other.
With data.frame
based track tables:
if (requireNamespace("dplyr", quietly = TRUE)) {
<- dplyr::filter(t_df, id == "1")
t_df1 <- dplyr::filter(t_df, id == "2")
t_df2 else {
} <- t_df[t_df$id == "1", ]
t_df1 <- t_df[t_df$id == "2", ]
t_df2
}
head(bind_tracks(t_df1, t_df2))
With tibble
based track tables:
if (requireNamespace("dplyr", quietly = TRUE)) {
<- dplyr::filter(t_tbl, id == "1")
t_tbl1 <- dplyr::filter(t_tbl, id == "2")
t_tbl2 else {
} <- t_tbl[t_tbl$id == "1", ]
t_tbl1 <- t_tbl[t_tbl$id == "2", ]
t_tbl2
}
bind_tracks(t_tbl1, t_tbl2)
With data.table
based track tables:
if (requireNamespace("dplyr", quietly = TRUE)) {
<- dplyr::filter(t_dt, id == "1")
t_dt1 <- dplyr::filter(t_dt, id == "2")
t_dt2 else {
} <- t_dt[t_dt$id == "1", ]
t_dt1 <- t_dt[t_dt$id == "2", ]
t_dt2
}
bind_tracks(t_dt1, t_dt2)
You can use any plotting method accepting a data.frame
,
a tibble
or a data.table
to represent the data
in a track table.
With base R:
plot(y ~ x, data = t_dt[t_dt$id == "1"], type = "l", col = "red",
xlim = range(t_dt$x), lwd = 2, asp = 1)
lines(y ~ x , data = t_dt[t_dt$id == "2"], col = "blue", lwd = 2)
With [ggplot2
]{https://ggplot2.tidyverse.org/}
if (requireNamespace("ggplot2", quietly = TRUE)) {
::ggplot(data = t_dt) +
ggplot2::aes(x = x, y = y, color = id) +
ggplot2::geom_path() +
ggplot2::coord_map()
ggplot2 }