Skip to content

Commit 0559ca0

Browse files
Merge pull request #344 from inbo/add-clock-sun-record-table
Add clock sun record table
2 parents f07d6d8 + 81da3e6 commit 0559ca0

File tree

5 files changed

+92
-4
lines changed

5 files changed

+92
-4
lines changed

DESCRIPTION

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: camtraptor
22
Title: Read, Explore and Visualize Camera Trap Data Packages
3-
Version: 0.26.0
3+
Version: 0.27.0
44
Authors@R: c(
55
person("Damiano", "Oldoni", , "damiano.oldoni@inbo.be", role = c("aut", "cre"),
66
comment = c(ORCID = "0000-0003-3445-7562")),
@@ -33,6 +33,7 @@ BugReports: https://github.com/inbo/camtraptor/issues
3333
Depends:
3434
R (>= 3.5.0)
3535
Imports:
36+
activity,
3637
assertthat,
3738
dplyr (>= 1.1.0),
3839
EML,
@@ -42,6 +43,7 @@ Imports:
4243
leaflet,
4344
lifecycle,
4445
lubridate,
46+
overlap,
4547
purrr,
4648
RColorBrewer,
4749
readr,

NEWS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# camtraptor 0.27.0
2+
3+
- `get_record_table()` returns now 4 new columns: `longitude`, `latitude` (deployment coordinates), `clock` (clock time of the observation in radians) and `solar` (sun time of the observation in radians) (#341).
4+
15
# camtraptor 0.26.0
26

37
- `get_custom_effort()` returns now the effort for each deployment separately (#333). The returned data frame has two new columns: `deploymentID` and `locationName`.

R/get_record_table.R

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
#' as defined in column `filePath` of `media`.
5858
#' - `Filename`: List, file names of the images linked to the given record,
5959
#' as defined in column `fileName` of `media`.
60+
#' - `Latitude`: Numeric, latitude of the station, based on `deploymentID` of the observations.
61+
#' - `Longitude`: Numeric, longitude of the station, based on `deploymentID` of the observations.
62+
#' - `clock`: Numeric, clock time in radians.
63+
#' - `solar`: Numeric, solar time in radians. Calculated using `overlap::sunTime`, which essentially uses the approach described in [Nouvellet et al. (2012)](https://doi.org/10.1111/j.1469-7998.2011.00864.x).
6064
#' @family exploration functions
6165
#' @importFrom dplyr .data %>%
6266
#' @importFrom rlang !! :=
@@ -172,6 +176,9 @@ get_record_table <- function(package = NULL,
172176
msg = "removeDuplicateRecords must be a logical: TRUE or FALSE."
173177
)
174178

179+
# Add coordinates to observations
180+
package <- add_coordinates(package)
181+
175182
# remove observations of unidentified individuals
176183
obs <- package$data$observations %>%
177184
dplyr::filter(!is.na(.data$scientificName))
@@ -180,6 +187,15 @@ get_record_table <- function(package = NULL,
180187
obs <- obs %>%
181188
dplyr::filter(!.data$scientificName %in% exclude)
182189

190+
191+
# Remove observations without timestamp and returns a warning message
192+
# if there are any
193+
if (any(is.na(obs$timestamp))) {
194+
warning("Some observations have no timestamp and will be removed.")
195+
obs <- obs %>%
196+
dplyr::filter(!is.na(.data$timestamp))
197+
}
198+
183199
# apply filtering on deployments
184200
deployments <- apply_filter_predicate(
185201
df = package$data$deployments,
@@ -276,6 +292,17 @@ get_record_table <- function(package = NULL,
276292
)) %>%
277293
dplyr::ungroup()
278294

295+
# Add clock time in radians
296+
record_table <- record_table %>%
297+
dplyr::mutate(clock = activity::gettime(.data$timestamp))
298+
# Add solar time in radians
299+
matrix_coords <- matrix(c(record_table$longitude, record_table$latitude),
300+
ncol = 2)
301+
record_table <- record_table %>%
302+
dplyr::mutate(solar = overlap::sunTime(.data$clock,
303+
.data$timestamp,
304+
matrix_coords))
305+
279306
record_table <- record_table %>%
280307
dplyr::rename(Station := !!stationCol,
281308
Species = "scientificName",
@@ -296,7 +323,11 @@ get_record_table <- function(package = NULL,
296323
"delta.time.hours",
297324
"delta.time.days",
298325
"Directory",
299-
"FileName"
326+
"FileName",
327+
"latitude",
328+
"longitude",
329+
"clock",
330+
"solar"
300331
)
301332
# remove duplicates if needed
302333
if (isTRUE(removeDuplicateRecords)) {
@@ -308,7 +339,9 @@ get_record_table <- function(package = NULL,
308339
.data$Date,
309340
.data$Time,
310341
.data$Directory,
311-
.data$FileName
342+
.data$FileName,
343+
.data$latitude,
344+
.data$longitude
312345
) %>%
313346
dplyr::mutate(row_number = dplyr::row_number()) %>%
314347
dplyr::filter(.data$delta.time.secs == max(.data$delta.time.secs) &

R/zzz.R

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,3 +1009,26 @@ order_cols_observations <- function(df) {
10091009
)
10101010
)
10111011
}
1012+
1013+
#' Add deployment coordinates to observations
1014+
#'
1015+
#' This function adds deployment coordinates to observations based on
1016+
#' `deploymentID`.
1017+
#'
1018+
#' @param package Camera trap data package object.
1019+
#' @return Camera trap data package object with `observations` updated.
1020+
#' @noRd
1021+
add_coordinates <- function(package) {
1022+
1023+
deployments <- package$data$deployments
1024+
observations <- package$data$observations
1025+
1026+
# add coordinates to observations
1027+
observations <- observations %>%
1028+
dplyr::left_join(deployments %>%
1029+
dplyr::select("deploymentID", "longitude", "latitude"),
1030+
by = "deploymentID")
1031+
1032+
package$data$observations <- observations
1033+
return(package)
1034+
}

tests/testthat/test-get_record_table.R

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ test_that("input of get_record_table, removeDuplicateRecords, is checked properl
5656
removeDuplicateRecords = NA
5757
))
5858
})
59+
test_that("warning is returned if some observations have no timestamp", {
60+
mica_no_timestamp <- mica
61+
mica_no_timestamp$data$observations$timestamp[3:5] <- NA
62+
expect_warning(
63+
get_record_table(mica_no_timestamp),
64+
"Some observations have no timestamp and will be removed."
65+
)
66+
})
5967

6068
test_that("right columns are returned", {
6169
expect_named(
@@ -72,7 +80,11 @@ test_that("right columns are returned", {
7280
"delta.time.hours",
7381
"delta.time.days",
7482
"Directory",
75-
"FileName"
83+
"FileName",
84+
"latitude",
85+
"longitude",
86+
"clock",
87+
"solar"
7688
)
7789
)
7890
})
@@ -209,6 +221,20 @@ test_that(paste(
209221
)
210222
})
211223

224+
test_that("clock is always in the range [0, 2*pi]", {
225+
clock_values <- get_record_table(mica) %>%
226+
dplyr::pull(clock)
227+
expect_true(all(clock_values >= 0))
228+
expect_true(all(clock_values <= 2 * pi))
229+
})
230+
231+
test_that("solar is always in the range [0, 2*pi]", {
232+
solar_values <- get_record_table(mica) %>%
233+
dplyr::pull(solar)
234+
expect_true(all(solar_values >= 0))
235+
expect_true(all(solar_values <= 2 * pi))
236+
})
237+
212238
test_that("filtering predicates are allowed and work well", {
213239
stations <- unique(
214240
suppressMessages(get_record_table(mica, pred_lt("longitude", 4.0)))$Station

0 commit comments

Comments
 (0)