Skip to content

Commit c95366a

Browse files
Merge pull request #1155 from M3nin0/fix/empty-segments
update `api_segments` to handle empty segments
2 parents e0d1ef5 + 524e38c commit c95366a

File tree

3 files changed

+71
-3
lines changed

3 files changed

+71
-3
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ Suggests:
105105
tmap (>= 3.3),
106106
torchopt (>= 0.1.2),
107107
tools,
108+
vctrs,
108109
xgboost
109110
Config/testthat/edition: 3
110111
Config/testthat/parallel: false

R/api_segments.R

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,9 @@
361361
ts_bands[["polygon_id"]] <- pol_id
362362
# we do the unnest again because we do not know the polygon id index
363363
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"]])
366367
# nest the values by bands
367368
ts_bands <- tidyr::nest(
368369
ts_bands,
@@ -401,6 +402,10 @@
401402
)
402403
}
403404
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+
}
404409
# set sits class
405410
class(samples) <- c("sits", class(samples))
406411
return(samples)
@@ -477,3 +482,61 @@
477482
})
478483
return(seg_tile_band_lst)
479484
}
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+

R/sits_segmentation.R

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ sits_segment <- function(cube,
8888
output_dir,
8989
version = "v1",
9090
progress = TRUE) {
91+
# check required package
92+
.check_require_packages("vctrs")
9193
# set caller for error msg
9294
.check_set_caller("sits_segment")
9395
# Preconditions
@@ -296,7 +298,9 @@ sits_slic <- function(data = NULL,
296298
# Get valid centers
297299
valid_centers <- slic[[2]][, 1] != 0 | slic[[2]][, 2] != 0
298300
# Bind valid centers with segments table
299-
v_obj <- cbind(v_obj, stats::na.omit(slic[[2]][valid_centers, ]))
301+
v_obj <- cbind(
302+
v_obj, matrix(stats::na.omit(slic[[2]][valid_centers, ]), ncol = 2)
303+
)
300304
# Rename columns
301305
names(v_obj) <- c("supercells", "x", "y", "geometry")
302306
# Get the extent of template raster

0 commit comments

Comments
 (0)