Skip to content

Commit

Permalink
Fixes documentation and adds tests
Browse files Browse the repository at this point in the history
  • Loading branch information
vwmaus committed Sep 18, 2023
1 parent 1ee7033 commit 3d55b28
Show file tree
Hide file tree
Showing 11 changed files with 258 additions and 73 deletions.
24 changes: 15 additions & 9 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Package: dtwSat
Type: Package
Title: Time-Weighted Dynamic Time Warping for Satellite Image Time Series Analysis
Version: 1.0.0
Date: 2023-09-03
Date: 2023-09-20
Authors@R:
c(person(given = "Victor",
family = "Maus",
Expand All @@ -24,14 +24,13 @@ Authors@R:
)
Description: Provides a robust approach to land use mapping using multi-dimensional
(multi-band) satellite image time series. By leveraging the Time-Weighted Dynamic
Time Warping (TWDTW) distance metric in tandem with a 1-NN classifier, the package
provides functions to produce land use maps based on distinct seasonality patterns,
typically observed in the phenological cycles of vegetation. The TWDTW algorithm is
described in Maus et al. (2016) <doi:10.1109/JSTARS.2016.2517118> and
Maus et al. (2019) <doi:10.18637/jss.v088.i05>. A key strength of TWDTW is its ability
to recognize patterns with only a minimal training set, achieving notable accuracy.
The package features tools for generating temporal patterns for various land cover types,
conducting land use mapping, and visualizing the outcomes.
Time Warping (TWDTW) distance metric in tandem with a 1 Nearest-Neighbor (1-NN) Classifier,
this package offers functions to produce land use maps based on distinct seasonality patterns,
commonly observed in the phenological cycles of vegetation. The approach is described in
Maus et al. (2016) <doi:10.1109/JSTARS.2016.2517118> and Maus et al. (2019) <doi:10.18637/jss.v088.i05>.
A primary advantage of TWDTW is its capability to handle irregularly sampled and noisy time series,
while also requiring minimal training sets. The package includes tools for training the 1-NN-TWDTW model,
visualizing temporal patterns, producing land use maps, and visualizing the results.
License: GPL (>= 3)
URL: https://github.com/vwmaus/dtwSat/
BugReports: https://github.com/vwmaus/dtwSat/issues/
Expand All @@ -54,3 +53,10 @@ Suggests:
rbenchmark,
testthat (>= 3.0.0)
Config/testthat/edition: 3
Collate:
'plot_patterns.R'
'predict.R'
'prepare_time_series.R'
'shift_dates.R'
'train.R'
'zzz.R'
8 changes: 6 additions & 2 deletions R/plot_patterns.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#'
#' @return A \code{\link[ggplot2]{ggplot}} object displaying the time series patterns.
#'
#' @seealso knn1_twdtw
#'
#' @inherit knn1_twdtw examples
#'
#' @export
plot.knn1_twdtw <- function(x, n = 12, ...) {

Expand All @@ -30,9 +34,9 @@ plot.knn1_twdtw <- function(x, n = 12, ...) {
df <- pivot_longer(df, !c('label', 'time'), names_to = "band", values_to = "value")

# Construct the ggplot
gp <- ggplot(df, aes(x = 'time', y = 'value', colour = 'band')) +
gp <- ggplot(df, aes(x = .data$time, y = .data$value, colour = .data$band)) +
geom_line() +
facet_wrap(~'label') +
facet_wrap(~label) +
theme(legend.position = "bottom") +
guides(colour = guide_legend(title = "Bands")) +
ylab("Value") +
Expand Down
3 changes: 3 additions & 0 deletions R/predict.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#'
#' @return A vector of predicted classes for the `newdata`.
#'
#' @seealso knn1_twdtw
#'
#' @inherit knn1_twdtw examples
#'
#' @export
predict.knn1_twdtw <- function(object, newdata, ...){
Expand Down
4 changes: 2 additions & 2 deletions R/prepare_time_series.R
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,12 @@ prepare_time_series <- function(x) {
if (!'label' %in% names(x)) {
x$label <- NA
}
x <- pivot_longer(x, !c(.data$ts_id, .data$label), names_to = "band_date", values_to = "value")
x <- pivot_longer(x, !c('ts_id', 'label'), names_to = 'band_date', values_to = 'value')
x$band <- rep(date_band$band, ns)
x$time <- rep(date_band$time, ns)
x$band_date <- NULL
result_df <- pivot_wider(x, id_cols = c('ts_id', 'label', 'time'), names_from = 'band', values_from = 'value')
result_df <- nest(result_df, .by = c(.data$ts_id, .data$label), .key = "observations")
result_df <- nest(result_df, .by = c('ts_id', 'label'), .key = 'observations')

return(result_df)

Expand Down
73 changes: 46 additions & 27 deletions R/train.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,47 @@
#' @return A 'knn1_twdtw' model containing the trained model information and the data used.
#'
#' @examples
#' \dontrun{
#' # Read training samples
#' samples <-
#' system.file("mato_grosso_brazil/samples.gpkg", package = "dtwSat") |>
#' st_read(quiet = TRUE)
#'
#' # Example will be added once the function is properly implemented and tested.
#'
#' # Get satellite image time sereis files
#' tif_files <- system.file("mato_grosso_brazil", package = "dtwSat") |>
#' dir(pattern = "\\.tif$", full.names = TRUE)
#'
#' # Get acquisition dates
#' acquisition_date <- regmatches(tif_files, regexpr("[0-9]{8}", tif_files)) |>
#' as.Date(format = "%Y%m%d")
#'
#' # Create a 2D datacube
#' dc <- read_stars(tif_files,
#' proxy = FALSE,
#' along = list(time = acquisition_date),
#' RasterIO = list(bands = 1:6)) |>
#' st_set_dimensions(3, c("EVI", "NDVI", "RED", "BLUE", "NIR", "MIR")) |>
#' split(c("band")) |>
#' split(c("time"))
#'
#' # Create a knn1-twdtw model
#' m <- knn1_twdtw(x = dc,
#' y = samples,
#' formula = band ~ s(time))
#'
#' # Visualize model patterns
#' plot(m)
#'
#' # Classify satellite images
#' system.time(
#' lu <- predict(dc,
#' model = m,
#' drop_dimensions = TRUE,
#' cycle_length = 'year',
#' time_scale = 'day',
#' time_weight = c(steepness = 0.1, midpoint = 50))
#' )
#' }
#' @export
knn1_twdtw <- function(x, y, formula = NULL, start_column = 'start_date',
end_column = 'end_date', label_colum = 'label',
Expand Down Expand Up @@ -74,7 +112,7 @@ knn1_twdtw <- function(x, y, formula = NULL, start_column = 'start_date',

# Split data frame by label
ts_data <- unnest(ts_data, cols = 'observations')
ts_data <- nest(ts_data, .by = .data$label, .key = "observations")
ts_data <- nest(ts_data, .by = 'label', .key = "observations")

# Define GAM function
gam_fun <- function(band, t, pred_t, formula, ...){
Expand Down Expand Up @@ -106,34 +144,15 @@ knn1_twdtw <- function(x, y, formula = NULL, start_column = 'start_date',

}

#' Compute the Most Common Sampling Frequency in a Stars Object
#' Compute the Most Common Sampling Frequency across all observations
#'
#' This function calculates the most common difference between consecutive time points in a stars object.
#' This can be useful for determining the sampling frequency of the time series data.
#' This function calculates the most common difference between consecutive time points.
#' This can be useful for determining the aproximate sampling frequency of the time series data.
#'
#' @param x A stars object containing time series data.
#' @param x A data frame including a column called `observations`` with the time series
#'
#' @return A difftime object representing the most common time difference between consecutive samples.
#'
#'
get_stars_time_freq <- function(x) {

# Extract the time dimension
time_values <- st_get_dimension_values(x, "time")

# Compute the differences between consecutive time points
time_diffs <- diff(time_values)

# Convert differences to days (while retaining the difftime class)
time_diffs <- as.difftime(time_diffs, units = "days")

# Identify the mode
mode_val_index <- which.max(tabulate(match(time_diffs, unique(time_diffs))))
freq <- diff(time_values[mode_val_index:(mode_val_index+1)])

return(freq)
}

get_time_series_freq <- function(x) {

# Extract the time dimension
Expand All @@ -151,4 +170,4 @@ get_time_series_freq <- function(x) {

return(freq)

}
}
18 changes: 0 additions & 18 deletions man/get_stars_time_freq.Rd

This file was deleted.

18 changes: 18 additions & 0 deletions man/get_time_series_freq.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 39 additions & 1 deletion man/knn1_twdtw.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions man/plot.knn1_twdtw.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions man/predict.knn1_twdtw.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3d55b28

Please sign in to comment.