Skip to content

Commit cf88cdc

Browse files
committed
added fill_na_values to align_move
1 parent 2e3a5f3 commit cf88cdc

File tree

5 files changed

+103
-28
lines changed

5 files changed

+103
-28
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
Package: moveVis
22
Type: Package
33
Title: Movement Data Visualization
4-
Version: 1.0.0
4+
Version: 1.0.1
55
Depends:
66
R (>= 3.5.0)
7-
Date: 2025-08-05
7+
Date: 2025-08-22
88
Authors@R: c(
99
person("Jakob", "Schwalb-Willmann", email = "[email protected]",
1010
role = c("aut", "cre"), comment = c(ORCID = "0000-0003-2665-1509")),

NEWS.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
***
22

3+
## moveVis 1.0.1
4+
Minor improvements.
5+
6+
**New features:**
7+
8+
* Added argument `fill_na_values` to `align_move` to allow control for whether `NA` values of columns at interpolated locations should be filled or not. `NA` values are filled with the value of the temporally closest location.
9+
10+
11+
<br>
12+
13+
***
14+
315
## moveVis 1.0.0
416
Updating `moveVis` to support `move2` for representing trajectory data and `terra` for representing raster data.
517

@@ -29,6 +41,10 @@ Updating `moveVis` to support `move2` for representing trajectory data and `terr
2941

3042
* `moveVis` was added to r-universe for continuous testing and integration. Like on CRAN, platform-specific binaries are build there to ease installation. You can now install the most recent `moveVis` version from r-universe using `install.packages("moveVis", repos = '16eagle.r-universe.dev')`
3143

44+
<br>
45+
46+
***
47+
3248
## moveVis 0.10.6
3349
New S3 class and methods to represent frames, lazy plotting, improvements.
3450

@@ -55,7 +71,6 @@ New S3 class and methods to represent frames, lazy plotting, improvements.
5571
* Fixed bug with paths crossing end of grid (aka dateline) when `cross_dateline=TRUE` in `frames_spatial()`
5672
* Fixing bug causing no path to be displayed at all when `tail_length=0` (now correctly showing points without tails)
5773

58-
5974
<br>
6075

6176
***

R/align_move.R

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
#'
77
#' @inheritParams frames_spatial
88
#' @param m \code{move2} object, which is allowed to contain irregular timestamps and diverging temporal resolutions.
9-
#' @param res either a \code{units} object representing the temporal resolution \code{m} should be aligned to, or a character being one of 'min', 'max', 'mean' or 'median' to indicate how the target resolution should be derived from \code{m}.
9+
#' @param res either a \code{units} object representing the temporal resolution \code{m} should be aligned to, or a character being one of 'minimum', 'maximum', 'mean' or 'median' to indicate how the target resolution should be derived from \code{m}.
1010
#' @param start_end_time \code{NULL} (default) or a vector of two POSIXct times (one start time and one end time for alignment). If \code{NULL}, the start and end time are retrieved from \code{m} and used for alignment.
1111
#' \itemize{
1212
#' \item \code{"minimum"} to use the smallest temporal resolution of \code{m} (default)
1313
#' \item \code{"maximum"} to use the largest temporal resolution of \code{m}
1414
#' \item \code{"mean"} to use the rounded average temporal resolution of \code{m}
1515
#' \item \code{"median"} to use the rounded median temporal resolution of \code{m}
1616
#' }
17+
#' @param fill_na_values logical, whether to fill empty (\code{NA}) values of columns of \code{m} at interpolated locations (defaults to \code{TRUE}). Column values at interpolated locations are filled with the value of the temporally closest location.
18+
#'
1719
#' @param ... deprecated arguments, including \code{digit}, \code{unit} and \code{spaceMethod}.
1820
#'
1921
#' @return \code{move2} object, with aligned positions at uniform temporal scale computed from \code{m}, ready to be used by \code{\link{frames_spatial}}.
@@ -70,22 +72,24 @@
7072
#'
7173
#' @export
7274

73-
align_move <- function(m, res = "minimum", start_end_time = NULL, ..., verbose = TRUE){
75+
align_move <- function(m, res = "minimum", start_end_time = NULL, fill_na_values = TRUE, ..., verbose = TRUE){
7476
if(inherits(verbose, "logical")) options(moveVis.verbose = verbose)
7577

7678
extras <- list(...)
7779
if(!is.null(extras$digit)) out("Argument 'digit' is deprecated. See ?moveVis::align_move for details.", type = 2)
7880
if(!is.null(extras$unit)) out("Argument 'unit' is deprecated. See ?moveVis::align_move for details.", type = 2)
7981
if(!is.null(extras$spaceMethod)) out("Argument 'spaceMethod' is deprecated. See ?moveVis::align_move for details.", type = 2)
8082

83+
if(!is.logical(fill_na_values)) fill_na_values <- TRUE
84+
8185
# check inputs
8286
.check_move2(m)
8387
m_tracks <- split(m, mt_track_id(m))
8488
m_length <- if(mt_n_tracks(m) > 1) sapply(split(m, mt_track_id(m)), nrow) else nrow(m)
8589
if(any(m_length < 2)) out(paste0("Individual track(s) ", paste0(which(m_length < 2), collapse = ", "), " of 'm' consist(s) of less than 2 locations. A minimum of 2 locations per indvidual track is required for alignment."), type = 3)
8690

8791
# check resolution and define resolution
88-
if(all(!c(inherits(res, "units"), inherits(res, "character")))) out("Argument 'res' must either be a 'units' object or one of c('min', 'max', 'mean', 'median').", type = 3)
92+
if(all(!c(inherits(res, "units"), inherits(res, "character")))) out("Argument 'res' must either be a 'units' object or one of c('minimum', 'maximum', 'mean', 'median').", type = 3)
8993
if(inherits(res, "units")){
9094
time_unit <- as_units("s")
9195
is_time_unit <- ud_are_convertible(deparse_unit(res), deparse_unit(time_unit))
@@ -177,6 +181,43 @@ align_move <- function(m, res = "minimum", start_end_time = NULL, ..., verbose =
177181
m_aligned <- m_aligned[order(m_aligned$timestamp),]
178182
m_aligned <- m_aligned[order(mt_track_id(m_aligned)),]
179183

184+
# fill variables
185+
if(isTRUE(fill_na_values)){
186+
m_aligend_filled <- lapply(split(m_aligned, mt_track_id(m_aligned)), function(m_track){
187+
for(x in names_attr){
188+
this_attr <- m_track[[x]]
189+
190+
m_track[[x]] <- sapply(1:length(this_attr), function(i){
191+
if(!is.na(this_attr[i])){
192+
this_attr[i]
193+
} else{
194+
left <- if(i == 1) NULL else 1:(i-1)
195+
right <- if(i == length(this_attr)) NULL else (i+1):length(this_attr)
196+
197+
if(!is.null(left)){
198+
non_na <- left[which(!is.na(this_attr[left]))[1]]
199+
} else non_na <- NULL
200+
if(!is.null(right)){
201+
non_na <- c(non_na, right[which(!is.na(this_attr[right]))[1]])
202+
}
203+
204+
non_na_diff <- abs(sapply(non_na, function(.non_na){
205+
difftime(
206+
m_track[[mt_time_column(m_track)]][.non_na],
207+
m_track[[mt_time_column(m_track)]][i],
208+
units = "secs"
209+
)
210+
}))
211+
212+
this_attr[non_na[which.min(non_na_diff)]]
213+
}
214+
})
215+
}
216+
return(m_track)
217+
})
218+
m_aligned <- do.call(rbind, m_aligend_filled)
219+
}
220+
180221
# for now, we just return the aligned data
181222
m_aligned <- m_aligned[m_aligned$interpolated,]
182223
m_aligned$interpolated <- NULL

man/align_move.Rd

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vignettes/example-2.Rmd

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,62 +5,72 @@ output: html_document
55

66
*Note: This vignette has not yet been updated to the most recent `moveVis` version. Displayed code will likely not work as it relies on deprecated dependencies such as `move` (replaced by `move2`) or `raster` (replaced by `terra`). For details, see the help pages of `moveVis` and the README as those resources have already been updated.*
77

8-
`moveVis` is entirely based on the `ggplot2` grammar of graphics. Each list element in `frames` is a `ggplot2` object that represents a single animation frame. Thus, it is possible to customize each frame individually using `ggplot2` functions. Instead, `moveVis` provides a set of functions for making it simpler to cutomize frames. We will use some of them in the following to customize `frames` that we created in the prior section:
8+
`moveVis` is entirely based on the `ggplot2` grammar of graphics. Each `moveVis` frame is rendered as a `ggplot2` object that represents a single animation frame. Thus, it is possible to customize each frame individually using `ggplot2` functions. Also, `moveVis` provides a set of functions for making it easier to customize frames. Let's create some `moveVis` frames and change their apperance:
99

1010
```R
1111
library(moveVis)
12-
library(move)
13-
library(raster)
12+
library(move2)
13+
library(sf)
1414
library(ggplot2)
1515

1616
data("move_data")
1717

1818
# align movement tracks
19-
move_data <- align_move(move_data, res = 4, unit = "mins")
19+
move_data <- align_move(move_data, res = units::set_units(4, "min"))
2020

2121
# create frames
2222
frames <- frames_spatial(move_data, path_colours = c("red", "green", "blue"),
23-
map_service = "osm", map_type = "watercolor", alpha = 0.5)
23+
map_service = "osm", map_type = "topographic", alpha = 0.5)
2424

2525
# edit frames
2626
frames <- add_labels(frames, x = "Longitude", y = "Latitude") # add labels, e.g. axis labels
2727
frames <- add_progress(frames) # add a progress bar
2828
frames <- add_scalebar(frames, height = 0.015) # add a scale bar
2929
frames <- add_northarrow(frames) # add a north arrow
30-
frames <- add_timestamps(frames, move_data, type = "label") # add timestamps
30+
frames <- add_timestamps(frames, type = "label") # add timestamps
3131
```
3232

3333
Alternatively, use the pipe, which (in my opinion) makes this more elegant:
3434

3535
```R
3636
# edit frames
37-
frames <- add_labels(frames, x = "Longitude", y = "Latitude") %>%
38-
add_progress() %>%
39-
add_scalebar(height = 0.015) %>%
40-
add_northarrow() %>%
41-
add_timestamps(move_data, type = "label")
37+
frames <- frames %>%
38+
add_labels(x = "Longitude", y = "Latitude") %>% # add labels, e.g. axis labels
39+
add_progress() %>% # add a progress bar
40+
add_scalebar(height = 0.015) %>% # add a scale bar
41+
add_northarrow() %>% # add a north arrow
42+
add_timestamps(type = "label") # add timestamps
4243

4344
## Have a look at one of the frames:
4445
frames[[100]]
4546
```
4647

4748
<p align="center"><img width="700" src="https://raw.githubusercontent.com/16EAGLE/AUX_data/master/data/moveVis_readme/readme_example2_01.png"></p>
4849

49-
For further details on these functions, please see their help files. If you want to apply your own `ggplot2` syntax to `frames`, e.g. for drawing polygons, lines or points that are static or even change with time, you can do this frame-wise. In the following example, we customize one individual frame just as if you would work with a single `ggplot2` object:
50+
It's also possible to apply your own `ggplot2` syntax to `frames`, e.g. for drawing polygons, lines or points that are static or change with time. Let's start with editing a single frame. In the following example, we create an `sf` polygon using Lat/Lon coordinates (EPSG:4326), transform it to Pseudo Mercator (EPSG 3857) to match the Coordinate Reference System of default basemaps, and add it to one individual frame:
5051

5152
```R
52-
data <- data.frame(x = c(8.917, 8.924, 8.924, 8.916, 8.917),
53-
y = c(47.7678, 47.7675, 47.764, 47.7646, 47.7678))
54-
55-
# just customize a single frame and have a look at it
56-
frame_test <- frames[[100]] + geom_path(aes(x = x, y = y), data = data,
57-
colour = "red", linetype = "dashed")
58-
frame_test
53+
data <- cbind(
54+
x = c(8.96, 8.955, 8.959, 8.963, 8.968, 8.963, 8.96),
55+
y = c(47.725, 47.728, 47.729, 47.728, 47.725, 47.723, 47.725)
56+
)
57+
58+
data <- list(data) %>%
59+
st_polygon() %>%
60+
st_geometry() %>%
61+
st_as_sf(crs = st_crs(4326)) %>%
62+
st_transform(crs = st_crs(3857))
63+
64+
frame_edited <- frames[[100]] + geom_sf(
65+
data = data, colour = "red", fill = "transparent",
66+
linetype = "dashed", lwd = 1
67+
) + coord_sf(expand = F)
68+
69+
frame_edited
5970
```
6071

6172
<p align="center"><img width="700" src="https://raw.githubusercontent.com/16EAGLE/AUX_data/master/data/moveVis_readme/readme_example2_02.png"></p>
6273

63-
6474
If you just want to change one or a small selection of frames, you could just manipulate those frames like shown above and assign the cusomized `ggplot2` frames to the equivalent elements in your `frames` list.
6575

6676
If you want to edit all frames, you can use the `add_gg()` function. Here, we want to mark a field on the map on all frames. For this, we use the `geom_path()` function of `ggplot2` with `add_gg()`:

0 commit comments

Comments
 (0)