|
361 | 361 | ts_bands[["polygon_id"]] <- pol_id
|
362 | 362 | # we do the unnest again because we do not know the polygon id index
|
363 | 363 | ts_bands <- tidyr::unnest(ts_bands, "time_series")
|
364 |
| - # remove pixels where all timeline was NA |
365 |
| - ts_bands <- tidyr::drop_na(ts_bands) |
| 364 | + # detect pixels where all timeline was NA |
| 365 | + na_polygons <- vctrs::vec_detect_complete(ts_bands) |
| 366 | + na_polygons <- unique(ts_bands[!na_polygons,][["polygon_id"]]) |
366 | 367 | # nest the values by bands
|
367 | 368 | ts_bands <- tidyr::nest(
|
368 | 369 | ts_bands,
|
|
401 | 402 | )
|
402 | 403 | }
|
403 | 404 | samples <- .discard(samples, "sample_id")
|
| 405 | + # fill NA samples |
| 406 | + if (length(na_polygons) > 0) { |
| 407 | + samples <- .segments_poilypoints_fill(samples, segments, na_polygons) |
| 408 | + } |
404 | 409 | # set sits class
|
405 | 410 | class(samples) <- c("sits", class(samples))
|
406 | 411 | return(samples)
|
|
477 | 482 | })
|
478 | 483 | return(seg_tile_band_lst)
|
479 | 484 | }
|
| 485 | +#' @title Fill ts data from polygon points. |
| 486 | +#' @name .segments_poilypoints_fill |
| 487 | +#' @keywords internal |
| 488 | +#' @noRd |
| 489 | +#' @param samples samples extracted from polygons |
| 490 | +#' @param segments large set of segments |
| 491 | +#' @param polygon_idx Index of NA polygons |
| 492 | +#' @return ts tibble |
| 493 | +#' |
| 494 | +.segments_poilypoints_fill <- function(samples, segments, polygon_idx) { |
| 495 | + # get polygons with NA values |
| 496 | + na_polygons <- dplyr::filter(segments, .data[["pol_id"]] %in% polygon_idx) |
| 497 | + # get neighbors geometries that touch polygons with NA values |
| 498 | + na_touches <- sf::st_touches(na_polygons, segments) |
| 499 | + # extract bands |
| 500 | + bands <- .ts_bands(.ts(samples)) |
| 501 | + # fill NA values |
| 502 | + na_touches <- purrr::map_dfr(seq_along(na_touches), function(touches_idx) { |
| 503 | + # get polygons and touches reference for the current polygon |
| 504 | + na_polygons_row <- na_polygons[touches_idx,] |
| 505 | + na_touched_row <- segments[na_touches[touches_idx][[1]],] |
| 506 | + # get samples associated with the NA polygon as reference |
| 507 | + samples_ref <- dplyr::filter( |
| 508 | + samples, .data[["polygon_id"]] == na_polygons_row[["pol_id"]] |
| 509 | + ) |
| 510 | + # define reference samples from where values will be extracted |
| 511 | + samples_row <- samples_ref |
| 512 | + # if neighbors are available, use their reference samples |
| 513 | + if (nrow(na_touched_row) > 0) { |
| 514 | + samples_row <- dplyr::filter( |
| 515 | + samples, .data[["polygon_id"]] %in% na_touched_row[["pol_id"]] |
| 516 | + ) |
| 517 | + } |
| 518 | + # expand time-series values to calculate median value |
| 519 | + samples_row_ts <- tidyr::unnest(samples_row, "time_series") |
| 520 | + # calculate temporal median and fill NA values with `0` |
| 521 | + samples_row_ts <- samples_row_ts |> |
| 522 | + dplyr::group_by(.data[["Index"]]) |> |
| 523 | + dplyr::summarize(dplyr::across( |
| 524 | + bands, stats::median, na.rm = TRUE) |
| 525 | + ) |> |
| 526 | + dplyr::mutate( |
| 527 | + dplyr::across(dplyr::everything(), ~tidyr::replace_na(., 0)) |
| 528 | + ) |
| 529 | + # spread the result across all points from the NA polygon |
| 530 | + samples_ref[["time_series"]] <- list(samples_row_ts) |
| 531 | + samples_ref |
| 532 | + }) |
| 533 | + # get samples from non-NA polygons |
| 534 | + samples <- dplyr::filter( |
| 535 | + samples, !.data[["polygon_id"]] %in% na_polygons[["pol_id"]] |
| 536 | + ) |
| 537 | + # bind result and return them |
| 538 | + dplyr::bind_rows( |
| 539 | + samples, na_touches |
| 540 | + ) |
| 541 | +} |
| 542 | + |
0 commit comments