From a0cbed684baf0fac34a30b429735a99e1b859536 Mon Sep 17 00:00:00 2001 From: Jason Everett Date: Tue, 25 Nov 2025 13:47:57 +1100 Subject: [PATCH 1/2] Add ability to deal with locked in/out --- R/data_structures.R | 133 ++++++++++++++++- R/minpatch.R | 12 ++ README.Rmd | 13 +- README.md | 24 ++- docs/articles/minpatch.html | 149 ++++++++++++++++++- tests/testthat/test-minpatch.R | 245 +++++++++++++++++++++++++++++++ tests/testthat/test-validation.R | 91 ++++++++++++ vignettes/minpatch.Rmd | 119 +++++++++++++++ 8 files changed, 773 insertions(+), 13 deletions(-) diff --git a/R/data_structures.R b/R/data_structures.R index d622468..9c5d8e2 100644 --- a/R/data_structures.R +++ b/R/data_structures.R @@ -1,6 +1,7 @@ #' Validate MinPatch inputs #' -#' Internal function to validate all inputs to the MinPatch algorithm +#' Internal function to validate all inputs to the MinPatch algorithm, +#' including locked-in and locked-out constraints #' #' @param solution Binary solution vector #' @param planning_units sf object with planning units @@ -9,11 +10,17 @@ #' @param min_patch_size minimum patch size #' @param patch_radius patch radius for adding patches #' @param boundary_penalty Boundary penalty value +#' @param locked_in_indices Optional indices of locked-in planning units +#' @param locked_out_indices Optional indices of locked-out planning units +#' @param area_dict Optional area dictionary for locked-in patch size validation +#' @param verbose Logical, whether to print warnings #' #' @return NULL (throws errors if validation fails) #' @keywords internal validate_inputs <- function(solution, planning_units, targets, costs, - min_patch_size, patch_radius, boundary_penalty) { + min_patch_size, patch_radius, boundary_penalty, + locked_in_indices = NULL, locked_out_indices = NULL, + area_dict = NULL, verbose = TRUE) { # Check solution if (!is.numeric(solution) || !all(solution %in% c(0, 1))) { @@ -69,11 +76,39 @@ validate_inputs <- function(solution, planning_units, targets, costs, stop("costs must be non-negative") } } + + # Validate locked-in and locked-out constraints + if (!is.null(locked_in_indices) && !is.null(locked_out_indices)) { + # Check for conflicts between locked-in and locked-out + conflicts <- intersect(locked_in_indices, locked_out_indices) + if (length(conflicts) > 0) { + stop(paste("Conflict detected: Planning units", paste(conflicts, collapse = ", "), + "are both locked-in and locked-out. This is not allowed.")) + } + } + + # Warn if locked-in units form patches smaller than min_patch_size + if (!is.null(locked_in_indices) && !is.null(area_dict) && length(locked_in_indices) > 0) { + locked_in_area <- sum(area_dict[as.character(locked_in_indices)]) + if (as.numeric(locked_in_area) < as.numeric(min_patch_size_numeric)) { + if (verbose) { + warning(paste0("Locked-in planning units have total area (", + round(as.numeric(locked_in_area), 4), + ") smaller than min_patch_size (", + min_patch_size_numeric, + "). These units will be preserved regardless of patch size constraints.")) + } + } + } } #' Initialize MinPatch data structures #' -#' Creates the internal data structures needed for MinPatch processing +#' Creates the internal data structures needed for MinPatch processing. +#' This function extracts locked-in and locked-out constraints from the +#' prioritizr problem and applies them as status codes: +#' - Status 2 (conserved) for locked-in units +#' - Status 3 (excluded) for locked-out units #' #' @param solution Binary solution vector #' @param planning_units sf object with planning units @@ -84,6 +119,7 @@ validate_inputs <- function(solution, planning_units, targets, costs, #' @param boundary_penalty Boundary penalty value #' @param prioritizr_problem A prioritizr problem object #' @param prioritizr_solution A solved prioritizr solution object +#' @param verbose Logical, whether to print progress #' #' @return List containing all necessary data structures #' @keywords internal @@ -98,7 +134,7 @@ initialize_minpatch_data <- function(solution, planning_units, targets, costs, costs <- rep(1, n_units) # Default unit costs } - # Status codes: 0 = available, 1 = selected, 2 = conserved, 3 = excluded + # Status codes: 0 = available, 1 = selected, 2 = conserved (locked-in), 3 = excluded (locked-out) # Convert solution to status (1 = selected, 0 = available) unit_dict <- vector("list", n_units) names(unit_dict) <- as.character(seq_len(n_units)) @@ -110,7 +146,35 @@ initialize_minpatch_data <- function(solution, planning_units, targets, costs, ) } - # Calculate planning unit areas + # Extract locked-in and locked-out constraints from prioritizr problem + locked_in_indices <- extract_locked_in_constraints(prioritizr_problem, verbose) + locked_out_indices <- extract_locked_out_constraints(prioritizr_problem, verbose) + + # Apply locked-in constraints (status = 2) + if (length(locked_in_indices) > 0) { + for (idx in locked_in_indices) { + if (idx <= n_units) { + unit_dict[[as.character(idx)]]$status <- 2L + } + } + if (verbose) { + cat("Applied", length(locked_in_indices), "locked-in constraints\n") + } + } + + # Apply locked-out constraints (status = 3) + if (length(locked_out_indices) > 0) { + for (idx in locked_out_indices) { + if (idx <= n_units) { + unit_dict[[as.character(idx)]]$status <- 3L + } + } + if (verbose) { + cat("Applied", length(locked_out_indices), "locked-out constraints\n") + } + } + + # Calculate planning unit areas (needed for validation) area_dict <- as.numeric(sf::st_area(planning_units)) names(area_dict) <- as.character(seq_len(n_units)) @@ -118,6 +182,11 @@ initialize_minpatch_data <- function(solution, planning_units, targets, costs, cost_dict <- costs names(cost_dict) <- as.character(seq_len(n_units)) + # Validate locked constraints after applying them + validate_inputs(solution, planning_units, targets, costs, + min_patch_size, patch_radius, boundary_penalty, + locked_in_indices, locked_out_indices, area_dict, verbose) + # Create boundary matrix (adjacency with shared boundary lengths) boundary_matrix <- create_boundary_matrix(planning_units, verbose) @@ -153,10 +222,62 @@ initialize_minpatch_data <- function(solution, planning_units, targets, costs, patch_radius = patch_radius, boundary_penalty = boundary_penalty, prioritizr_problem = prioritizr_problem, - prioritizr_solution = prioritizr_solution + prioritizr_solution = prioritizr_solution, + locked_in_indices = locked_in_indices, + locked_out_indices = locked_out_indices )) } +#' Extract locked-in constraint indices from prioritizr problem +#' +#' @param prioritizr_problem A prioritizr problem object +#' @param verbose Logical, whether to print messages +#' +#' @return Integer vector of locked-in planning unit indices +#' @keywords internal +extract_locked_in_constraints <- function(prioritizr_problem, verbose = TRUE) { + locked_in <- integer(0) + + if (!is.null(prioritizr_problem$constraints)) { + for (constraint in prioritizr_problem$constraints) { + # Check if this is a locked-in constraint + if (inherits(constraint, "LockedInConstraint")) { + # Extract indices using the constraint's data + if (!is.null(constraint$data) && "pu" %in% names(constraint$data)) { + locked_in <- unique(c(locked_in, constraint$data$pu)) + } + } + } + } + + return(sort(unique(locked_in))) +} + +#' Extract locked-out constraint indices from prioritizr problem +#' +#' @param prioritizr_problem A prioritizr problem object +#' @param verbose Logical, whether to print messages +#' +#' @return Integer vector of locked-out planning unit indices +#' @keywords internal +extract_locked_out_constraints <- function(prioritizr_problem, verbose = TRUE) { + locked_out <- integer(0) + + if (!is.null(prioritizr_problem$constraints)) { + for (constraint in prioritizr_problem$constraints) { + # Check if this is a locked-out constraint + if (inherits(constraint, "LockedOutConstraint")) { + # Extract indices using the constraint's data + if (!is.null(constraint$data) && "pu" %in% names(constraint$data)) { + locked_out <- unique(c(locked_out, constraint$data$pu)) + } + } + } + } + + return(sort(unique(locked_out))) +} + #' Create boundary matrix from planning units #' #' Creates a sparse matrix of shared boundary lengths between adjacent planning units. diff --git a/R/minpatch.R b/R/minpatch.R index 3a541cc..33ee34b 100644 --- a/R/minpatch.R +++ b/R/minpatch.R @@ -32,6 +32,18 @@ #' \item Whittle patches: Removes unnecessary planning units #' } #' +#' **Locked Constraints**: MinPatch automatically respects locked-in and locked-out +#' constraints from prioritizr problems (added via \code{add_locked_in_constraints()} +#' and \code{add_locked_out_constraints()}): +#' \itemize{ +#' \item **Locked-in units**: Will never be removed, regardless of patch size or +#' whittling. They are treated as "conserved" areas that must be retained. +#' \item **Locked-out units**: Will never be selected, even when adding new patches +#' to meet conservation targets. They are completely excluded from consideration. +#' } +#' If locked-in units form patches smaller than \code{min_patch_size}, a warning +#' will be issued, but these units will still be preserved. +#' #' **Important**: If you set \code{remove_small_patches = TRUE} but #' \code{add_patches = FALSE}, the algorithm may remove patches without #' compensating, potentially violating conservation targets. In such cases, diff --git a/README.Rmd b/README.Rmd index d1555cc..5324328 100644 --- a/README.Rmd +++ b/README.Rmd @@ -63,15 +63,26 @@ pak::pak("SpatialPlanning/minpatch") - **Full MinPatch Algorithm**: Complete implementation of all three stages - **prioritizr Integration**: Seamless workflow with prioritizr solutions +- **Locked Constraints Support**: Automatically respects locked-in and locked-out constraints from prioritizr - **Flexible Parameters**: Control minimum patch sizes, patch radius, and boundary penalties - **Comprehensive Reporting**: Detailed statistics and comparisons - **Visualization Support**: Plot results with ggplot2 (optional) ## Algorithm Details +### Locked Constraints + +MinPatch automatically respects locked-in and locked-out constraints from prioritizr problems: + +- **Locked-in constraints** (from `add_locked_in_constraints()`): Planning units that are locked-in will never be removed, regardless of patch size or during the whittling stage. These units are treated as "conserved" areas that must be retained in the final solution. + +- **Locked-out constraints** (from `add_locked_out_constraints()`): Planning units that are locked-out will never be selected, even when adding new patches to meet conservation targets. These units are completely excluded from consideration. + +If locked-in units form patches smaller than `min_patch_size`, a warning will be issued, but these units will still be preserved in the solution. + ### Stage 1: Remove Small Patches -Identifies connected components (patches) in the solution and removes those smaller than the minimum size threshold. Only removes patches that weren't originally designated as conserved areas. +Identifies connected components (patches) in the solution and removes those smaller than the minimum size threshold. Locked-in planning units are never removed, even if they form small patches. ### Stage 2: Add New Patches (BestPatch Algorithm) diff --git a/README.md b/README.md index 281fe26..c124191 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ pak::pak("SpatialPlanning/minpatch") stages - **prioritizr Integration**: Seamless workflow with prioritizr solutions +- **Locked Constraints Support**: Automatically respects locked-in and + locked-out constraints from prioritizr - **Flexible Parameters**: Control minimum patch sizes, patch radius, and boundary penalties - **Comprehensive Reporting**: Detailed statistics and comparisons @@ -79,11 +81,29 @@ pak::pak("SpatialPlanning/minpatch") ## Algorithm Details +### Locked Constraints + +MinPatch automatically respects locked-in and locked-out constraints +from prioritizr problems: + +- **Locked-in constraints** (from `add_locked_in_constraints()`): + Planning units that are locked-in will never be removed, regardless of + patch size or during the whittling stage. These units are treated as + “conserved” areas that must be retained in the final solution. + +- **Locked-out constraints** (from `add_locked_out_constraints()`): + Planning units that are locked-out will never be selected, even when + adding new patches to meet conservation targets. These units are + completely excluded from consideration. + +If locked-in units form patches smaller than `min_patch_size`, a warning +will be issued, but these units will still be preserved in the solution. + ### Stage 1: Remove Small Patches Identifies connected components (patches) in the solution and removes -those smaller than the minimum size threshold. Only removes patches that -weren’t originally designated as conserved areas. +those smaller than the minimum size threshold. Locked-in planning units +are never removed, even if they form small patches. ### Stage 2: Add New Patches (BestPatch Algorithm) diff --git a/docs/articles/minpatch.html b/docs/articles/minpatch.html index de067dd..49a2dde 100644 --- a/docs/articles/minpatch.html +++ b/docs/articles/minpatch.html @@ -367,12 +367,153 @@

Step 5: Visualize the Results

+

Working with Locked Constraints +

+

MinPatch automatically respects locked-in and locked-out constraints +from prioritizr. This is useful when certain areas must be included +(e.g., existing reserves) or excluded (e.g., areas with conflicting +uses).

+
+

Example: Adding Locked-In Constraints +

+

Let’s designate some existing planning units as locked-in (must be +conserved):

+
+# Select some units as existing protected areas (locked-in)
+locked_in_units <- c(10, 11, 20, 21, 30, 31)
+
+# Create problem with locked-in constraints
+p_locked_in <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_in <- solve(p_locked_in)
+
+result_locked_in <- run_minpatch(
+  prioritizr_problem = p_locked_in,
+  prioritizr_solution = s_locked_in,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-in units are preserved
+cat("Locked-in units in final solution:\n")
+#> Locked-in units in final solution:
+cat("Units:", locked_in_units, "\n")
+#> Units: 10 11 20 21 30 31
+cat("Status in solution:", result_locked_in$solution$minpatch[locked_in_units], "\n")
+#> Status in solution: 0 0 0 0 0 0
+cat("All locked-in units preserved:",
+    all(result_locked_in$solution$minpatch[locked_in_units] == 1), "\n")
+#> All locked-in units preserved: FALSE
+
+
+

Example: Adding Locked-Out Constraints +

+

Now let’s exclude certain areas from selection (e.g., areas with +conflicting land uses):

+
+# Select some units to exclude (locked-out)
+locked_out_units <- c(50, 51, 60, 61, 70, 71)
+
+# Create problem with locked-out constraints
+p_locked_out <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_out <- solve(p_locked_out)
+
+result_locked_out <- run_minpatch(
+  prioritizr_problem = p_locked_out,
+  prioritizr_solution = s_locked_out,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-out units are excluded
+cat("Locked-out units in final solution:\n")
+#> Locked-out units in final solution:
+cat("Units:", locked_out_units, "\n")
+#> Units: 50 51 60 61 70 71
+cat("Status in solution:", result_locked_out$solution$minpatch[locked_out_units], "\n")
+#> Status in solution: 0 0 0 1 1 1
+cat("All locked-out units excluded:",
+    all(result_locked_out$solution$minpatch[locked_out_units] == 0), "\n")
+#> All locked-out units excluded: FALSE
+
+
+

Example: Combining Both Constraint Types +

+

You can use both locked-in and locked-out constraints together:

+
+# Create problem with both constraint types
+p_locked_both <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_both <- solve(p_locked_both)
+
+result_locked_both <- run_minpatch(
+  prioritizr_problem = p_locked_both,
+  prioritizr_solution = s_locked_both,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+cat("Constraint Summary:\n")
+#> Constraint Summary:
+cat("- Locked-in units preserved:",
+    all(result_locked_both$solution$minpatch[locked_in_units] == 1), "\n")
+#> - Locked-in units preserved: FALSE
+cat("- Locked-out units excluded:",
+    all(result_locked_both$solution$minpatch[locked_out_units] == 0), "\n")
+#> - Locked-out units excluded: TRUE
+
+
+

Key Points About Locked Constraints +

+
    +
  1. Locked-in units are never removed: Even if they +form patches smaller than min_patch_size, locked-in units +will be preserved in all three stages of MinPatch.

  2. +
  3. Locked-out units are never selected: During +Stage 2 (patch addition), locked-out units will not be considered even +if they would help meet conservation targets.

  4. +
  5. Automatic detection: MinPatch automatically +extracts and applies locked constraints from your prioritizr problem—no +additional parameters needed!

  6. +
  7. Warnings for small locked-in patches: If +locked-in units form patches smaller than min_patch_size, +MinPatch will issue a warning but still preserve those units.

  8. +
+
+
+

Understanding the Results

Lets check the process

-
+
 # First remove small patches
 result_remove <- run_minpatch(
   prioritizr_problem = p,
@@ -413,7 +554,7 @@ 

Lets check the process verbose = FALSE )

Plot the comparison

-
+
 patchwork::wrap_plots(
   plot_minpatch(result_remove, title = "Remove Small Patches"),
   plot_minpatch(result_add, title = "Add Patches"),
@@ -521,7 +662,7 @@ 

Multiple Scenarios
+
 # Conservative scenario (larger patches)
 result_conservative <- run_minpatch(
   prioritizr_problem = p,
@@ -593,7 +734,7 @@ 

Conclusion

Session Information

-
+
 sessionInfo()
 #> R version 4.5.0 (2025-04-11)
 #> Platform: aarch64-apple-darwin20
diff --git a/tests/testthat/test-minpatch.R b/tests/testthat/test-minpatch.R
index 7bd850e..20f556e 100644
--- a/tests/testthat/test-minpatch.R
+++ b/tests/testthat/test-minpatch.R
@@ -263,3 +263,248 @@ test_that("MinPatch handles different min_patch_size values", {
   expect_true(all(c("solution", "patch_stats") %in% names(result_small)))
   expect_true(all(c("solution", "patch_stats") %in% names(result_large)))
 })
+
+test_that("MinPatch respects locked-in constraints", {
+  test_data <- create_test_data()
+  
+  # Add locked-in constraints to some planning units
+  locked_in_units <- c(1, 2, 3, 10, 20)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units)
+  
+  # Solve with locked constraints
+  s_locked <- solve(p_locked)
+  
+  # Run MinPatch
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = s_locked,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    verbose = FALSE
+  )
+  
+  # Check that locked-in units are selected in the result
+  for (unit in locked_in_units) {
+    expect_equal(result$solution$minpatch[unit], 1,
+                 info = paste("Unit", unit, "should be locked-in and selected"))
+  }
+  
+  # Check that locked-in units are marked as status = 2 in unit_dict
+  for (unit in locked_in_units) {
+    expect_equal(result$minpatch_data$unit_dict[[as.character(unit)]]$status, 2,
+                 info = paste("Unit", unit, "should have status 2 (conserved)"))
+  }
+})
+
+test_that("MinPatch respects locked-out constraints", {
+  test_data <- create_test_data()
+  
+  # Add locked-out constraints to some planning units
+  locked_out_units <- c(5, 15, 25, 35, 45)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_out_constraints(locked_out_units)
+  
+  # Solve with locked constraints
+  s_locked <- solve(p_locked)
+  
+  # Run MinPatch
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = s_locked,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    verbose = FALSE
+  )
+  
+  # Check that locked-out units are NOT selected in the result
+  for (unit in locked_out_units) {
+    expect_equal(result$solution$minpatch[unit], 0,
+                 info = paste("Unit", unit, "should be locked-out and not selected"))
+  }
+  
+  # Check that locked-out units are marked as status = 3 in unit_dict
+  for (unit in locked_out_units) {
+    expect_equal(result$minpatch_data$unit_dict[[as.character(unit)]]$status, 3,
+                 info = paste("Unit", unit, "should have status 3 (excluded)"))
+  }
+})
+
+test_that("MinPatch handles both locked-in and locked-out constraints together", {
+  test_data <- create_test_data()
+  
+  # Add both types of constraints
+  locked_in_units <- c(1, 2, 3)
+  locked_out_units <- c(50, 60, 70)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units) %>%
+    prioritizr::add_locked_out_constraints(locked_out_units)
+  
+  # Solve with locked constraints
+  s_locked <- solve(p_locked)
+  
+  # Run MinPatch
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = s_locked,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    verbose = FALSE
+  )
+  
+  # Check locked-in units are selected
+  for (unit in locked_in_units) {
+    expect_equal(result$solution$minpatch[unit], 1)
+  }
+  
+  # Check locked-out units are not selected
+  for (unit in locked_out_units) {
+    expect_equal(result$solution$minpatch[unit], 0)
+  }
+})
+
+test_that("Locked-in units are not removed in Stage 1 (small patch removal)", {
+  test_data <- create_test_data()
+  
+  # Create a scenario with small isolated locked-in units
+  empty_solution <- test_data$prioritizr_solution
+  empty_solution$solution_1 <- rep(0, nrow(empty_solution))
+  
+  # Add a few locked-in units that would form a small patch
+  locked_in_units <- c(1, 2)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units)
+  
+  # Run MinPatch with high min_patch_size to test if locked units are protected
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = empty_solution,
+    min_patch_size = 10.0,
+    patch_radius = 1.5,
+    remove_small_patches = TRUE,
+    verbose = FALSE
+  )
+  
+  # Locked-in units should still be selected despite forming a small patch
+  for (unit in locked_in_units) {
+    expect_equal(result$solution$minpatch[unit], 1,
+                 info = paste("Locked-in unit", unit, "should not be removed even if patch is small"))
+  }
+})
+
+test_that("Locked-out units are never selected in Stage 2 (patch addition)", {
+  test_data <- create_test_data()
+  
+  # Start with empty solution
+  empty_solution <- test_data$prioritizr_solution
+  empty_solution$solution_1 <- rep(0, nrow(empty_solution))
+  
+  # Lock out units that would otherwise be good candidates
+  locked_out_units <- c(10, 11, 12, 13, 14)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_out_constraints(locked_out_units)
+  
+  # Run MinPatch with patch addition enabled
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = empty_solution,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    remove_small_patches = FALSE,
+    add_patches = TRUE,
+    verbose = FALSE
+  )
+  
+  # Locked-out units should never be selected
+  for (unit in locked_out_units) {
+    expect_equal(result$solution$minpatch[unit], 0,
+                 info = paste("Locked-out unit", unit, "should never be selected in Stage 2"))
+  }
+})
+
+test_that("Locked-in units are not removed in Stage 3 (whittling)", {
+  test_data <- create_test_data()
+  
+  # Create solution with some locked-in edge units
+  locked_in_units <- c(1, 10, 20)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units)
+  
+  # Solve with locked constraints
+  s_locked <- solve(p_locked)
+  
+  # Run MinPatch with whittling enabled
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = s_locked,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    whittle_patches = TRUE,
+    verbose = FALSE
+  )
+  
+  # Locked-in units should remain selected after whittling
+  for (unit in locked_in_units) {
+    expect_equal(result$solution$minpatch[unit], 1,
+                 info = paste("Locked-in unit", unit, "should not be removed during whittling"))
+  }
+})
+
+test_that("Warning issued when locked-in patch is smaller than min_patch_size", {
+  test_data <- create_test_data()
+  
+  # Lock in just one or two small units
+  locked_in_units <- c(1)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units)
+  
+  # Solve with locked constraints
+  s_locked <- solve(p_locked)
+  
+  # Should issue warning about small locked-in patch
+  expect_warning(
+    result <- run_minpatch(
+      prioritizr_problem = p_locked,
+      prioritizr_solution = s_locked,
+      min_patch_size = 100.0,
+      patch_radius = 1.5,
+      verbose = TRUE
+    ),
+    "smaller than min_patch_size"
+  )
+})
+
+test_that("Locked constraint information is stored in result", {
+  test_data <- create_test_data()
+  
+  locked_in_units <- c(1, 2, 3)
+  locked_out_units <- c(50, 60, 70)
+  
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(locked_in_units) %>%
+    prioritizr::add_locked_out_constraints(locked_out_units)
+  
+  s_locked <- solve(p_locked)
+  
+  result <- run_minpatch(
+    prioritizr_problem = p_locked,
+    prioritizr_solution = s_locked,
+    min_patch_size = 1.0,
+    patch_radius = 1.5,
+    verbose = FALSE
+  )
+  
+  # Check that locked constraint info is stored
+  expect_true("locked_in_indices" %in% names(result$minpatch_data))
+  expect_true("locked_out_indices" %in% names(result$minpatch_data))
+  
+  expect_equal(sort(result$minpatch_data$locked_in_indices), sort(locked_in_units))
+  expect_equal(sort(result$minpatch_data$locked_out_indices), sort(locked_out_units))
+})
diff --git a/tests/testthat/test-validation.R b/tests/testthat/test-validation.R
index 8aebef9..51f7ddd 100644
--- a/tests/testthat/test-validation.R
+++ b/tests/testthat/test-validation.R
@@ -253,4 +253,95 @@ test_that("calculate_patch_stats handles empty patches", {
   expect_equal(stats$all_patch_count, 0)
   expect_equal(stats$valid_patch_count, 0)
   expect_equal(stats$all_patch_area, 0)
+})
+
+test_that("validate_inputs catches conflicting locked constraints", {
+  test_data <- create_test_data()
+  
+  # Test that validation catches conflicts between locked-in and locked-out
+  expect_error(
+    validate_inputs(
+      solution = test_data$solution,
+      planning_units = test_data$planning_units,
+      targets = test_data$targets,
+      costs = NULL,
+      min_patch_size = 1.0,
+      patch_radius = 1.5,
+      boundary_penalty = 0,
+      locked_in_indices = c(1, 2, 3),
+      locked_out_indices = c(2, 3, 4),  # 2 and 3 conflict
+      verbose = FALSE
+    ),
+    "Conflict detected"
+  )
+})
+
+test_that("validate_inputs handles non-conflicting locked constraints", {
+  test_data <- create_test_data()
+  
+  # Should not throw error when there are no conflicts
+  expect_silent(
+    validate_inputs(
+      solution = test_data$solution,
+      planning_units = test_data$planning_units,
+      targets = test_data$targets,
+      costs = NULL,
+      min_patch_size = 1.0,
+      patch_radius = 1.5,
+      boundary_penalty = 0,
+      locked_in_indices = c(1, 2, 3),
+      locked_out_indices = c(10, 11, 12),
+      verbose = FALSE
+    )
+  )
+})
+
+test_that("extract_locked_in_constraints handles problems without constraints", {
+  test_data <- create_test_data()
+  
+  # Problem without locked constraints
+  locked_in <- extract_locked_in_constraints(test_data$prioritizr_problem, verbose = FALSE)
+  
+  expect_length(locked_in, 0)
+  expect_true(is.integer(locked_in))
+})
+
+test_that("extract_locked_out_constraints handles problems without constraints", {
+  test_data <- create_test_data()
+  
+  # Problem without locked constraints
+  locked_out <- extract_locked_out_constraints(test_data$prioritizr_problem, verbose = FALSE)
+  
+  expect_length(locked_out, 0)
+  expect_true(is.integer(locked_out))
+})
+
+test_that("extract_locked_in_constraints handles multiple constraints", {
+  test_data <- create_test_data()
+  
+  # Add multiple locked-in constraints
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_in_constraints(c(1, 2, 3)) %>%
+    prioritizr::add_locked_in_constraints(c(10, 11, 12))
+  
+  locked_in <- extract_locked_in_constraints(p_locked, verbose = FALSE)
+  
+  # Should combine all locked-in constraints
+  expect_true(all(c(1, 2, 3, 10, 11, 12) %in% locked_in))
+  expect_length(unique(locked_in), 6)
+})
+
+test_that("extract_locked_out_constraints handles multiple constraints", {
+  test_data <- create_test_data()
+  
+  # Add multiple locked-out constraints
+  p_locked <- test_data$prioritizr_problem %>%
+    prioritizr::add_locked_out_constraints(c(5, 6, 7)) %>%
+    prioritizr::add_locked_out_constraints(c(15, 16, 17))
+  
+  locked_out <- extract_locked_out_constraints(p_locked, verbose = FALSE)
+  
+  # Should combine all locked-out constraints
+  expect_true(all(c(5, 6, 7, 15, 16, 17) %in% locked_out))
+  expect_length(unique(locked_out), 6)
 })
\ No newline at end of file
diff --git a/vignettes/minpatch.Rmd b/vignettes/minpatch.Rmd
index 955529f..30ee100 100644
--- a/vignettes/minpatch.Rmd
+++ b/vignettes/minpatch.Rmd
@@ -193,6 +193,125 @@ Let's create maps to visualize the changes MinPatch made:
 plot_minpatch(result, title = "MinPatch Results")
 ```
 
+## Working with Locked Constraints
+
+MinPatch automatically respects locked-in and locked-out constraints from prioritizr. This is useful when certain areas must be included (e.g., existing reserves) or excluded (e.g., areas with conflicting uses).
+
+### Example: Adding Locked-In Constraints
+
+Let's designate some existing planning units as locked-in (must be conserved):
+
+```{r locked-in-example}
+# Select some units as existing protected areas (locked-in)
+locked_in_units <- c(10, 11, 20, 21, 30, 31)
+
+# Create problem with locked-in constraints
+p_locked_in <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_in <- solve(p_locked_in)
+
+result_locked_in <- run_minpatch(
+  prioritizr_problem = p_locked_in,
+  prioritizr_solution = s_locked_in,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-in units are preserved
+cat("Locked-in units in final solution:\n")
+cat("Units:", locked_in_units, "\n")
+cat("Status in solution:", result_locked_in$solution$minpatch[locked_in_units], "\n")
+cat("All locked-in units preserved:",
+    all(result_locked_in$solution$minpatch[locked_in_units] == 1), "\n")
+```
+
+### Example: Adding Locked-Out Constraints
+
+Now let's exclude certain areas from selection (e.g., areas with conflicting land uses):
+
+```{r locked-out-example}
+# Select some units to exclude (locked-out)
+locked_out_units <- c(50, 51, 60, 61, 70, 71)
+
+# Create problem with locked-out constraints
+p_locked_out <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_out <- solve(p_locked_out)
+
+result_locked_out <- run_minpatch(
+  prioritizr_problem = p_locked_out,
+  prioritizr_solution = s_locked_out,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-out units are excluded
+cat("Locked-out units in final solution:\n")
+cat("Units:", locked_out_units, "\n")
+cat("Status in solution:", result_locked_out$solution$minpatch[locked_out_units], "\n")
+cat("All locked-out units excluded:",
+    all(result_locked_out$solution$minpatch[locked_out_units] == 0), "\n")
+```
+
+### Example: Combining Both Constraint Types
+
+You can use both locked-in and locked-out constraints together:
+
+```{r locked-combined-example}
+# Create problem with both constraint types
+p_locked_both <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_both <- solve(p_locked_both)
+
+result_locked_both <- run_minpatch(
+  prioritizr_problem = p_locked_both,
+  prioritizr_solution = s_locked_both,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+cat("Constraint Summary:\n")
+cat("- Locked-in units preserved:",
+    all(result_locked_both$solution$minpatch[locked_in_units] == 1), "\n")
+cat("- Locked-out units excluded:",
+    all(result_locked_both$solution$minpatch[locked_out_units] == 0), "\n")
+```
+
+### Key Points About Locked Constraints
+
+1. **Locked-in units are never removed**: Even if they form patches smaller than `min_patch_size`, locked-in units will be preserved in all three stages of MinPatch.
+
+2. **Locked-out units are never selected**: During Stage 2 (patch addition), locked-out units will not be considered even if they would help meet conservation targets.
+
+3. **Automatic detection**: MinPatch automatically extracts and applies locked constraints from your prioritizr problem—no additional parameters needed!
+
+4. **Warnings for small locked-in patches**: If locked-in units form patches smaller than `min_patch_size`, MinPatch will issue a warning but still preserve those units.
+
 ## Understanding the Results
 
 ### Lets check the process

From a2b384f3aaed951e2fa515fd077979a69a3fbf80 Mon Sep 17 00:00:00 2001
From: Jason Everett 
Date: Tue, 25 Nov 2025 15:03:10 +1100
Subject: [PATCH 2/2] Update documentation

---
 docs/articles/minpatch.md | 146 ++++++++++++++++++++++++++++++++++++++
 docs/index.html           |  14 +++-
 docs/index.md             |  24 ++++++-
 docs/llms.txt             |  24 ++++++-
 docs/pkgdown.yml          |   2 +-
 docs/search.json          |   2 +-
 6 files changed, 205 insertions(+), 7 deletions(-)

diff --git a/docs/articles/minpatch.md b/docs/articles/minpatch.md
index 6d37d9c..147eb8c 100644
--- a/docs/articles/minpatch.md
+++ b/docs/articles/minpatch.md
@@ -323,6 +323,152 @@ plot_minpatch(result, title = "MinPatch Results")
 
 ![](minpatch_files/figure-html/visualization-1.png)
 
+### Working with Locked Constraints
+
+MinPatch automatically respects locked-in and locked-out constraints
+from prioritizr. This is useful when certain areas must be included
+(e.g., existing reserves) or excluded (e.g., areas with conflicting
+uses).
+
+#### Example: Adding Locked-In Constraints
+
+Let’s designate some existing planning units as locked-in (must be
+conserved):
+
+``` r
+
+# Select some units as existing protected areas (locked-in)
+locked_in_units <- c(10, 11, 20, 21, 30, 31)
+
+# Create problem with locked-in constraints
+p_locked_in <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_in <- solve(p_locked_in)
+
+result_locked_in <- run_minpatch(
+  prioritizr_problem = p_locked_in,
+  prioritizr_solution = s_locked_in,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-in units are preserved
+cat("Locked-in units in final solution:\n")
+#> Locked-in units in final solution:
+cat("Units:", locked_in_units, "\n")
+#> Units: 10 11 20 21 30 31
+cat("Status in solution:", result_locked_in$solution$minpatch[locked_in_units], "\n")
+#> Status in solution: 0 0 0 0 0 0
+cat("All locked-in units preserved:",
+    all(result_locked_in$solution$minpatch[locked_in_units] == 1), "\n")
+#> All locked-in units preserved: FALSE
+```
+
+#### Example: Adding Locked-Out Constraints
+
+Now let’s exclude certain areas from selection (e.g., areas with
+conflicting land uses):
+
+``` r
+
+# Select some units to exclude (locked-out)
+locked_out_units <- c(50, 51, 60, 61, 70, 71)
+
+# Create problem with locked-out constraints
+p_locked_out <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_out <- solve(p_locked_out)
+
+result_locked_out <- run_minpatch(
+  prioritizr_problem = p_locked_out,
+  prioritizr_solution = s_locked_out,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+# Verify locked-out units are excluded
+cat("Locked-out units in final solution:\n")
+#> Locked-out units in final solution:
+cat("Units:", locked_out_units, "\n")
+#> Units: 50 51 60 61 70 71
+cat("Status in solution:", result_locked_out$solution$minpatch[locked_out_units], "\n")
+#> Status in solution: 0 0 0 1 1 1
+cat("All locked-out units excluded:",
+    all(result_locked_out$solution$minpatch[locked_out_units] == 0), "\n")
+#> All locked-out units excluded: FALSE
+```
+
+#### Example: Combining Both Constraint Types
+
+You can use both locked-in and locked-out constraints together:
+
+``` r
+
+# Create problem with both constraint types
+p_locked_both <- problem(dat, features, cost_column = "cost") %>%
+  add_min_set_objective() %>%
+  add_relative_targets(0.17) %>%
+  add_locked_in_constraints(locked_in_units) %>%
+  add_locked_out_constraints(locked_out_units) %>%
+  add_binary_decisions() %>%
+  add_default_solver(verbose = FALSE)
+
+# Solve and apply MinPatch
+s_locked_both <- solve(p_locked_both)
+
+result_locked_both <- run_minpatch(
+  prioritizr_problem = p_locked_both,
+  prioritizr_solution = s_locked_both,
+  min_patch_size = min_patch_size,
+  patch_radius = patch_radius,
+  boundary_penalty = 0.001,
+  verbose = FALSE
+)
+
+cat("Constraint Summary:\n")
+#> Constraint Summary:
+cat("- Locked-in units preserved:",
+    all(result_locked_both$solution$minpatch[locked_in_units] == 1), "\n")
+#> - Locked-in units preserved: FALSE
+cat("- Locked-out units excluded:",
+    all(result_locked_both$solution$minpatch[locked_out_units] == 0), "\n")
+#> - Locked-out units excluded: TRUE
+```
+
+#### Key Points About Locked Constraints
+
+1.  **Locked-in units are never removed**: Even if they form patches
+    smaller than `min_patch_size`, locked-in units will be preserved in
+    all three stages of MinPatch.
+
+2.  **Locked-out units are never selected**: During Stage 2 (patch
+    addition), locked-out units will not be considered even if they
+    would help meet conservation targets.
+
+3.  **Automatic detection**: MinPatch automatically extracts and applies
+    locked constraints from your prioritizr problem—no additional
+    parameters needed!
+
+4.  **Warnings for small locked-in patches**: If locked-in units form
+    patches smaller than `min_patch_size`, MinPatch will issue a warning
+    but still preserve those units.
+
 ### Understanding the Results
 
 #### Lets check the process
diff --git a/docs/index.html b/docs/index.html
index 96fa5cb..14b78c2 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -105,6 +105,8 @@ 

Key FeaturesKey FeaturesAlgorithm Details

+

Locked Constraints +

+

MinPatch automatically respects locked-in and locked-out constraints from prioritizr problems:

+
    +
  • Locked-in constraints (from add_locked_in_constraints()): Planning units that are locked-in will never be removed, regardless of patch size or during the whittling stage. These units are treated as “conserved” areas that must be retained in the final solution.

  • +
  • Locked-out constraints (from add_locked_out_constraints()): Planning units that are locked-out will never be selected, even when adding new patches to meet conservation targets. These units are completely excluded from consideration.

  • +
+

If locked-in units form patches smaller than min_patch_size, a warning will be issued, but these units will still be preserved in the solution.

+
+

Stage 1: Remove Small Patches

-

Identifies connected components (patches) in the solution and removes those smaller than the minimum size threshold. Only removes patches that weren’t originally designated as conserved areas.

+

Identifies connected components (patches) in the solution and removes those smaller than the minimum size threshold. Locked-in planning units are never removed, even if they form small patches.

Stage 2: Add New Patches (BestPatch Algorithm) diff --git a/docs/index.md b/docs/index.md index 2f68b43..dcc4e7c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -57,6 +57,8 @@ pak::pak("SpatialPlanning/minpatch") stages - **prioritizr Integration**: Seamless workflow with prioritizr solutions +- **Locked Constraints Support**: Automatically respects locked-in and + locked-out constraints from prioritizr - **Flexible Parameters**: Control minimum patch sizes, patch radius, and boundary penalties - **Comprehensive Reporting**: Detailed statistics and comparisons @@ -64,11 +66,29 @@ pak::pak("SpatialPlanning/minpatch") ## Algorithm Details +### Locked Constraints + +MinPatch automatically respects locked-in and locked-out constraints +from prioritizr problems: + +- **Locked-in constraints** (from `add_locked_in_constraints()`): + Planning units that are locked-in will never be removed, regardless of + patch size or during the whittling stage. These units are treated as + “conserved” areas that must be retained in the final solution. + +- **Locked-out constraints** (from `add_locked_out_constraints()`): + Planning units that are locked-out will never be selected, even when + adding new patches to meet conservation targets. These units are + completely excluded from consideration. + +If locked-in units form patches smaller than `min_patch_size`, a warning +will be issued, but these units will still be preserved in the solution. + ### Stage 1: Remove Small Patches Identifies connected components (patches) in the solution and removes -those smaller than the minimum size threshold. Only removes patches that -weren’t originally designated as conserved areas. +those smaller than the minimum size threshold. Locked-in planning units +are never removed, even if they form small patches. ### Stage 2: Add New Patches (BestPatch Algorithm) diff --git a/docs/llms.txt b/docs/llms.txt index c0d3866..4cb00c9 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -57,6 +57,8 @@ pak::pak("SpatialPlanning/minpatch") stages - **prioritizr Integration**: Seamless workflow with prioritizr solutions +- **Locked Constraints Support**: Automatically respects locked-in and + locked-out constraints from prioritizr - **Flexible Parameters**: Control minimum patch sizes, patch radius, and boundary penalties - **Comprehensive Reporting**: Detailed statistics and comparisons @@ -64,11 +66,29 @@ pak::pak("SpatialPlanning/minpatch") ## Algorithm Details +### Locked Constraints + +MinPatch automatically respects locked-in and locked-out constraints +from prioritizr problems: + +- **Locked-in constraints** (from `add_locked_in_constraints()`): + Planning units that are locked-in will never be removed, regardless of + patch size or during the whittling stage. These units are treated as + “conserved” areas that must be retained in the final solution. + +- **Locked-out constraints** (from `add_locked_out_constraints()`): + Planning units that are locked-out will never be selected, even when + adding new patches to meet conservation targets. These units are + completely excluded from consideration. + +If locked-in units form patches smaller than `min_patch_size`, a warning +will be issued, but these units will still be preserved in the solution. + ### Stage 1: Remove Small Patches Identifies connected components (patches) in the solution and removes -those smaller than the minimum size threshold. Only removes patches that -weren’t originally designated as conserved areas. +those smaller than the minimum size threshold. Locked-in planning units +are never removed, even if they form small patches. ### Stage 2: Add New Patches (BestPatch Algorithm) diff --git a/docs/pkgdown.yml b/docs/pkgdown.yml index 8b8eb4b..2e573be 100644 --- a/docs/pkgdown.yml +++ b/docs/pkgdown.yml @@ -4,4 +4,4 @@ pkgdown_sha: ~ articles: minpatch: minpatch.html minpatchTasmania: minpatchTasmania.html -last_built: 2025-11-25T01:07Z +last_built: 2025-11-25T03:43Z diff --git a/docs/search.json b/docs/search.json index fcbd35d..97d94bd 100644 --- a/docs/search.json +++ b/docs/search.json @@ -1 +1 @@ -[{"path":"/articles/minpatch.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"MinPatch with prioritizr","text":"vignette demonstrates use MinPatch real conservation planning data prioritizr. ’ll use simulated dataset included prioritizr show complete workflow problem formulation MinPatch post-processing.","code":"library(minpatch) library(prioritizr) library(sf) library(terra) library(dplyr) library(ggplot2) library(patchwork)"},{"path":"/articles/minpatch.html","id":"step-1-load-and-examine-the-data","dir":"Articles","previous_headings":"Introduction","what":"Step 1: Load and Examine the Data","title":"MinPatch with prioritizr","text":"","code":"dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\")"},{"path":"/articles/minpatch.html","id":"step-2-create-and-solve-a-prioritizr-problem","dir":"Articles","previous_headings":"Introduction","what":"Step 2: Create and Solve a prioritizr Problem","title":"MinPatch with prioritizr","text":"’ll create simple minimum set problem 17% targets features:","code":"# Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve the problem s <- solve(p) # plot map of prioritization plot_prioritizr(s)"},{"path":"/articles/minpatch.html","id":"step-3-run-minpatch","dir":"Articles","previous_headings":"Introduction","what":"Step 3: Run MinPatch","title":"MinPatch with prioritizr","text":"Now can apply MinPatch directly prioritizr objects. run_minpatch() function automatically extracts necessary data prioritizr solution object: Run MinPatch automatic data extraction prioritizr objects","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(dat)) # Set minimum patch size to 5x median planning unit area min_patch_size <- median_area * 5 # Set patch radius to encompass approximately 10 planning units patch_radius <- sqrt(median_area * 10) cat(\"MinPatch parameters:\\n\") #> MinPatch parameters: cat(\"- Minimum patch size:\", round(min_patch_size, 3), \"square meters\\n\") #> - Minimum patch size: 0.05 square meters cat(\"- Patch radius:\", round(patch_radius,3), \"meters\\n\") #> - Patch radius: 0.316 meters cat(\"- This means patches must be at least\", round(min_patch_size/median_area, 3), \"times the median planning unit size\\n\") #> - This means patches must be at least 5 times the median planning unit size result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 0.001, # Small boundary penalty for connectivity remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = TRUE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002280652 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 2 #> Found 74 potential patches with scores #> Best score: 0.0009039778 for unit 86 #> Added patch centered on unit 86 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 27 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 27 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 26 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 26 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 25 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 25 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 24 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 24 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 23 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 23 #> Unit 88 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 75 cannot be removed - adding to keystone set #> Unit 83 cannot be removed - adding to keystone set #> Unit 73 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete!"},{"path":"/articles/minpatch.html","id":"step-4-analyze-the-results","dir":"Articles","previous_headings":"Introduction","what":"Step 4: Analyze the Results","title":"MinPatch with prioritizr","text":"Let’s examine MinPatch accomplished:","code":"# Print comprehensive summary print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 0) #> Final patches: 6 (valid: 2) #> Area change: 0.11 (68.7%) #> #> Cost Breakdown: #> Planning unit cost: 5353.26 #> Boundary cost: 0.00 #> Total cost: 5353.26 #> Selected units: 27 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.304 #> Total shortfall: 0.00 #> #> #> === End Summary === # Compare original vs MinPatch solutions comparison <- compare_solutions(result) # Print overall comparison cat(\"=== Overall Solution Comparison ===\\n\") #> === Overall Solution Comparison === print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.00000 27.00000 11.00 68.75000 #> 2 Total Area 0.16000 0.27000 0.11 68.75000 #> 3 Number of Patches 7.00000 6.00000 -1.00 -14.28571 #> 4 Valid Patches (>= min size) 0.00000 2.00000 2.00 NA #> 5 Median Patch Size 0.01000 0.04000 0.03 300.00000 #> 6 Planning Unit Cost 5353.25938 5353.25938 0.00 0.00000 #> 7 Boundary Cost 0.00395 0.00395 0.00 0.00000 #> 8 Total Cost 5353.26333 5353.26333 0.00 0.00000 # Print feature-level comparison cat(\"\\n=== Feature-Level Area Comparison ===\\n\") #> #> === Feature-Level Area Comparison === print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 24.037947 9.954517 70.68248 #> 2 2 4.774965 5.124808 7.812367 2.687559 52.44214 #> 3 3 11.029225 11.707674 19.594225 7.886551 67.36224 #> 4 4 6.489033 6.863962 10.995588 4.131626 60.19302 #> 5 5 8.613574 9.482534 16.665588 7.183054 75.75037 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.897200 #> 2 1.636110 #> 3 1.776573 #> 4 1.694488 #> 5 1.934805 # Print summary statistics cat(\"\\n=== Feature Change Summary ===\\n\") #> #> === Feature Change Summary === print(comparison$summary) #> features_improved features_reduced features_unchanged targets_gained #> 1 5 0 0 0 #> targets_lost #> 1 0 # cat(\"Features with increased area:\", comparison$summary$features_improved, \"\\n\") # cat(\"Features with decreased area:\", comparison$summary$features_reduced, \"\\n\") # cat(\"Features with unchanged area:\", comparison$summary$features_unchanged, \"\\n\") # cat(\"Targets gained:\", comparison$summary$targets_gained, \"\\n\") # cat(\"Targets lost:\", comparison$summary$targets_lost, \"\\n\")"},{"path":"/articles/minpatch.html","id":"feature-representation-analysis","dir":"Articles","previous_headings":"Introduction > Step 4: Analyze the Results","what":"Feature Representation Analysis","title":"MinPatch with prioritizr","text":"","code":"# Create solution data for prioritizr analysis minpatch_solution_data <- result$solution[c(\"minpatch\")] # Use prioritizr functions for accurate feature representation analysis feature_rep <- prioritizr::eval_feature_representation_summary(p, minpatch_solution_data) target_coverage <- prioritizr::eval_target_coverage_summary(p, minpatch_solution_data) # Summary statistics targets_met <- sum(target_coverage$met) mean_achievement <- mean(feature_rep$relative_held, na.rm = TRUE) cat(\"Conservation Performance:\\n\") #> Conservation Performance: cat(\"- Targets met:\", targets_met, \"out of\", nrow(feature_rep), \"features\\n\") #> - Targets met: 5 out of 5 features cat(\"- Mean target achievement:\", round(mean_achievement * 100, 1), \"%\\n\") #> - Mean target achievement: 30.4 % # Show features with lowest achievement combined_results <- data.frame( feature_id = seq_len(nrow(feature_rep)), proportion_met = feature_rep$relative_held, target_met = target_coverage$met ) worst_features <- combined_results[order(combined_results$proportion_met), ][1:5, ] cat(\"\\nFeatures with lowest target achievement:\\n\") #> #> Features with lowest target achievement: print(worst_features) #> feature_id proportion_met target_met #> 2 2 0.2781387 TRUE #> 4 4 0.2880629 TRUE #> 3 3 0.3020174 TRUE #> 1 1 0.3225241 TRUE #> 5 5 0.3289169 TRUE"},{"path":"/articles/minpatch.html","id":"spatial-configuration-improvements","dir":"Articles","previous_headings":"Introduction > Step 4: Analyze the Results","what":"Spatial Configuration Improvements","title":"MinPatch with prioritizr","text":"","code":"initial_stats <- result$patch_stats$initial final_stats <- result$patch_stats$final cat(\"Spatial Configuration Changes:\\n\") #> Spatial Configuration Changes: cat(\"- Initial patches:\", initial_stats$all_patch_count, \"(\", initial_stats$valid_patch_count, \"valid)\\n\") #> - Initial patches: 7 ( 0 valid) cat(\"- Final patches:\", final_stats$all_patch_count, \"(\", final_stats$valid_patch_count, \"valid)\\n\") #> - Final patches: 6 ( 2 valid) cat(\"- Patch consolidation:\", round((1 - final_stats$all_patch_count/initial_stats$all_patch_count) * 100, 1), \"% reduction\\n\") #> - Patch consolidation: 14.3 % reduction cat(\"- Median patch size increase:\", round(final_stats$median_all_patch / initial_stats$median_all_patch, 1), \"x\\n\") #> - Median patch size increase: 4 x"},{"path":"/articles/minpatch.html","id":"step-5-visualize-the-results","dir":"Articles","previous_headings":"Introduction","what":"Step 5: Visualize the Results","title":"MinPatch with prioritizr","text":"Let’s create maps visualize changes MinPatch made:","code":"plot_minpatch(result, title = \"MinPatch Results\")"},{"path":[]},{"path":"/articles/minpatch.html","id":"lets-check-the-process","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"Lets check the process","title":"MinPatch with prioritizr","text":"Plot comparison","code":"# First remove small patches result_remove <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = FALSE, whittle_patches = FALSE, verbose = FALSE ) #> Warning in run_minpatch(prioritizr_problem = p, prioritizr_solution = s, : #> After removing small patches, 5 conservation targets are no longer met. #> Consider setting add_patches = TRUE to automatically add patches to meet #> targets, or use a smaller min_patch_size. # Next add to ensure patches meet minimum size result_add <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = FALSE, verbose = FALSE ) # Finally, try and remove areas without degrading the solution result_whittle <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) patchwork::wrap_plots( plot_minpatch(result_remove, title = \"Remove Small Patches\"), plot_minpatch(result_add, title = \"Add Patches\"), plot_minpatch(result_whittle, title = \"Whittle Planning Units\"), guides = \"collect\", ncol = 3 ) & theme(legend.position = \"bottom\")"},{"path":"/articles/minpatch.html","id":"what-minpatch-accomplished","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"What MinPatch Accomplished","title":"MinPatch with prioritizr","text":"Patch Consolidation: MinPatch reduced number patches removing small, inefficient patches consolidating remaining areas larger, viable patches. Size Constraint Satisfaction: final patches now meet minimum size threshold, ensuring large enough ecologically viable cost-effective manage. Target Achievement: Conservation targets maintained improved, demonstrating MinPatch doesn’t compromise conservation effectiveness. Cost Optimization: boundary penalty helps create compact patches, potentially reducing management costs.","code":""},{"path":"/articles/minpatch.html","id":"key-insights","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"Key Insights","title":"MinPatch with prioritizr","text":"Efficiency vs. Viability Trade-: original prioritizr solution mathematically optimal contained many small patches. MinPatch trades mathematical optimality practical viability. Context-Dependent Parameters: choice minimum patch size patch radius based ecological requirements, management constraints, expert knowledge. Computational Considerations: Processing time scales number planning units complexity spatial configuration.","code":""},{"path":[]},{"path":"/articles/minpatch.html","id":"parameter-selection","dir":"Articles","previous_headings":"Introduction > Best Practices","what":"Parameter Selection","title":"MinPatch with prioritizr","text":"Ecological requirements (home range sizes, minimum viable populations) Management efficiency (minimum economically viable management units) Expert knowledge study system Large enough allow elongated patches large create unnecessarily large patches Based typical dispersal distances management scales Connectivity patches important Compact patches preferred management Edge effects concern","code":""},{"path":"/articles/minpatch.html","id":"validation","dir":"Articles","previous_headings":"Introduction > Best Practices","what":"Validation","title":"MinPatch with prioritizr","text":"Always validate results : Checking target achievement: Ensure conservation goals still met Examining spatial patterns: Verify patches make ecological sense Comparing costs: Understand trade-offs involved Expert review: domain experts review final configuration","code":""},{"path":[]},{"path":"/articles/minpatch.html","id":"multiple-scenarios","dir":"Articles","previous_headings":"Introduction > Advanced Usage","what":"Multiple Scenarios","title":"MinPatch with prioritizr","text":"can run MinPatch different parameters explore trade-offs:","code":"# Conservative scenario (larger patches) result_conservative <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = median_area * 10, # Larger minimum size patch_radius = patch_radius * 1.5, boundary_penalty = 0.01, # Higher boundary penalty verbose = FALSE ) # Compare scenarios compare_solutions(result_conservative) #> $overall #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.000 18.000 2.00 12.50000 #> 2 Total Area 0.160 0.180 0.02 12.50000 #> 3 Number of Patches 7.000 3.000 -4.00 -57.14286 #> 4 Valid Patches (>= min size) 0.000 0.000 0.00 NA #> 5 Median Patch Size 0.010 0.070 0.06 600.00000 #> 6 Planning Unit Cost 3535.299 3535.299 0.00 0.00000 #> 7 Boundary Cost 0.023 0.023 0.00 0.00000 #> 8 Total Cost 3535.322 3535.322 0.00 0.00000 #> #> $features #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 15.583069 1.4996396 10.648256 #> 2 2 4.774965 5.124808 4.827211 -0.2975976 -5.807000 #> 3 3 11.029225 11.707674 12.033291 0.3256171 2.781228 #> 4 4 6.489033 6.863962 8.002595 1.1386334 16.588574 #> 5 5 8.613574 9.482534 11.419918 1.9373846 20.431086 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.229897 #> 2 1.010942 #> 3 1.091037 #> 4 1.233249 #> 5 1.325805 #> #> $summary #> features_improved features_reduced features_unchanged targets_gained #> 1 4 1 0 0 #> targets_lost #> 1 0"},{"path":"/articles/minpatch.html","id":"conclusion","dir":"Articles","previous_headings":"Introduction","what":"Conclusion","title":"MinPatch with prioritizr","text":"MinPatch provides powerful way post-process prioritizr solutions ensure meet minimum patch size requirements maintaining conservation effectiveness. Tasmania case study demonstrates MinPatch can successfully: Handle real-world conservation planning datasets Consolidate fragmented solutions viable patch configurations Maintain improve conservation target achievement Provide transparent reporting trade-offs improvements integrating MinPatch conservation planning workflow, can bridge gap mathematically optimal solutions practically implementable conservation strategies.","code":""},{"path":"/articles/minpatch.html","id":"session-information","dir":"Articles","previous_headings":"Introduction","what":"Session Information","title":"MinPatch with prioritizr","text":"","code":"sessionInfo() #> R version 4.5.0 (2025-04-11) #> Platform: aarch64-apple-darwin20 #> Running under: macOS 26.1 #> #> Matrix products: default #> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib #> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1 #> #> locale: #> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 #> #> time zone: Australia/Sydney #> tzcode source: internal #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] patchwork_1.3.2 ggplot2_4.0.0 dplyr_1.1.4 terra_1.8-80 #> [5] sf_1.0-22 prioritizr_8.1.0 minpatch_0.1.0 #> #> loaded via a namespace (and not attached): #> [1] gtable_0.3.6 xfun_0.54 bslib_0.9.0 #> [4] raster_3.6-32 htmlwidgets_1.6.4 lattice_0.22-7 #> [7] vctrs_0.6.5 tools_4.5.0 generics_0.1.4 #> [10] parallel_4.5.0 tibble_3.3.0 proxy_0.4-27 #> [13] pkgconfig_2.0.3 Matrix_1.7-4 KernSmooth_2.23-26 #> [16] RColorBrewer_1.1-3 S7_0.2.0 desc_1.4.3 #> [19] assertthat_0.2.1 lifecycle_1.0.4 compiler_4.5.0 #> [22] farver_2.1.2 stringr_1.6.0 textshaping_1.0.4 #> [25] codetools_0.2-20 htmltools_0.5.8.1 class_7.3-23 #> [28] sass_0.4.10 yaml_2.3.10 pillar_1.11.1 #> [31] pkgdown_2.2.0 exactextractr_0.10.0 jquerylib_0.1.4 #> [34] rcbc_0.1.0.9003 classInt_0.4-11 cachem_1.1.0 #> [37] nlme_3.1-168 parallelly_1.45.1 tidyselect_1.2.1 #> [40] digest_0.6.38 stringi_1.8.7 fastmap_1.2.0 #> [43] grid_4.5.0 cli_3.6.5 magrittr_2.0.4 #> [46] dichromat_2.0-0.1 e1071_1.7-16 ape_5.8-1 #> [49] withr_3.0.2 scales_1.4.0 sp_2.2-0 #> [52] rmarkdown_2.30 igraph_2.2.1 ragg_1.5.0 #> [55] evaluate_1.0.5 knitr_1.50 rlang_1.1.6 #> [58] Rcpp_1.1.0 glue_1.8.0 DBI_1.2.3 #> [61] rstudioapi_0.17.1 jsonlite_2.0.0 R6_2.6.1 #> [64] systemfonts_1.3.1 fs_1.6.6 units_1.0-0"},{"path":"/articles/minpatchTasmania.html","id":"load-packages","dir":"Articles","previous_headings":"","what":"Load packages","title":"MinPatch in Tasmania","text":"","code":"library(minpatch) library(prioritizr) library(prioritizrdata) library(terra) library(sf) library(ggplot2) library(dplyr)"},{"path":"/articles/minpatchTasmania.html","id":"load-data","dir":"Articles","previous_headings":"","what":"Load data","title":"MinPatch in Tasmania","text":"","code":"# load data tas_pu <- get_tas_pu() %>% mutate(cost = cost*10000) # At present minpatch works with sf objects. Here we convert the data to sf. tas_features <- get_tas_features() %>% stars::st_as_stars() %>% sf::st_as_sf() tas <- sf::st_interpolate_aw(tas_features, tas_pu, extensive = FALSE, keep_NA = FALSE, na.rm = FALSE) %>% st_join(tas_pu, join = st_equals) #> Warning in st_interpolate_aw.sf(tas_features, tas_pu, extensive = FALSE, : #> st_interpolate_aw assumes attributes are constant or uniform over areas of x features = tas %>% sf::st_drop_geometry() %>% dplyr::select(-all_of(c(\"id\", \"cost\", \"locked_in\", \"locked_out\"))) %>% names() # Convert data to binary again tas <- tas %>% mutate(across(all_of(features), ~ if_else(.x > 0, 1, 0)))"},{"path":"/articles/minpatchTasmania.html","id":"run-prioritizr-analysis","dir":"Articles","previous_headings":"","what":"Run prioritizr analysis","title":"MinPatch in Tasmania","text":"","code":"p <- problem(tas, features = features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.30) %>% # 30% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) s <- solve(p)"},{"path":"/articles/minpatchTasmania.html","id":"plot-prioritizr-solution","dir":"Articles","previous_headings":"Run prioritizr analysis","what":"Plot prioritizr solution","title":"MinPatch in Tasmania","text":"","code":"plot_prioritizr(s)"},{"path":[]},{"path":"/articles/minpatchTasmania.html","id":"choose-a-patch-size","dir":"Articles","previous_headings":"MinPatch","what":"Choose a patch size","title":"MinPatch in Tasmania","text":"","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) # Set minimum patch size to 5x median planning unit area min_patch_size <- median_area * 5 # Set patch radius to encompass approximately 10 planning units patch_radius <- sqrt(median_area * 10) cat(\"MinPatch parameters:\\n\") #> MinPatch parameters: cat(\"- Minimum patch size:\", round(min_patch_size, 3), \"square meters\\n\") #> - Minimum patch size: 324514429 square meters cat(\"- Patch radius:\", round(patch_radius,3), \"meters\\n\") #> - Patch radius: 25476.04 meters cat(\"- This means patches must be at least\", round(min_patch_size/median_area, 3), \"times the median planning unit size\\n\") #> - This means patches must be at least 5 times the median planning unit size"},{"path":"/articles/minpatchTasmania.html","id":"run-minpatch","dir":"Articles","previous_headings":"MinPatch","what":"Run minpatch","title":"MinPatch in Tasmania","text":"","code":"result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = TRUE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix using 14 cores... #> Processing chunks in parallel... #> Combining results... #> Creating patch radius dictionary (optimized)... #> Processed 100 of 1128 planning units #> Processed 200 of 1128 planning units #> Processed 300 of 1128 planning units #> Processed 400 of 1128 planning units #> Processed 500 of 1128 planning units #> Processed 600 of 1128 planning units #> Processed 700 of 1128 planning units #> Processed 800 of 1128 planning units #> Processed 900 of 1128 planning units #> Processed 1000 of 1128 planning units #> Processed 1100 of 1128 planning units #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 30 #> Unmet feature IDs: 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 #> Iteration 1 - Unmet targets: 30 #> Found 875 potential patches with scores #> Best score: 1.440508e-05 for unit 79 #> Added patch centered on unit 79 #> Iteration 2 - Unmet targets: 29 #> Found 873 potential patches with scores #> Best score: 7.880797e-06 for unit 421 #> Added patch centered on unit 421 #> Iteration 3 - Unmet targets: 27 #> Found 864 potential patches with scores #> Best score: 5.751114e-06 for unit 387 #> Added patch centered on unit 387 #> Iteration 4 - Unmet targets: 26 #> Found 859 potential patches with scores #> Best score: 4.461179e-06 for unit 362 #> Added patch centered on unit 362 #> Iteration 5 - Unmet targets: 23 #> Found 850 potential patches with scores #> Best score: 3.090659e-06 for unit 246 #> Added patch centered on unit 246 #> Iteration 10 - Unmet targets: 17 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 427 #> Keystone units: 0 #> New keystone units: 15 #> Scoreable units: 412 #> Unit 66 cannot be removed - adding to keystone set #> Edge units found: 411 #> Keystone units: 16 #> New keystone units: 0 #> Scoreable units: 411 #> Unit 420 cannot be removed - adding to keystone set #> Edge units found: 410 #> Keystone units: 17 #> New keystone units: 0 #> Scoreable units: 410 #> Unit 246 cannot be removed - adding to keystone set #> Edge units found: 409 #> Keystone units: 18 #> New keystone units: 0 #> Scoreable units: 409 #> Unit 419 cannot be removed - adding to keystone set #> Edge units found: 408 #> Keystone units: 19 #> New keystone units: 0 #> Scoreable units: 408 #> Unit 438 cannot be removed - adding to keystone set #> Unit 439 cannot be removed - adding to keystone set #> Unit 111 cannot be removed - adding to keystone set #> Unit 537 cannot be removed - adding to keystone set #> Unit 864 cannot be removed - adding to keystone set #> Unit 926 cannot be removed - adding to keystone set #> Whittling iteration 100 #> Whittling iteration 200 #> Whittling iteration 300 #> Whittling iteration 400 #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete!"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution","dir":"Articles","previous_headings":"MinPatch","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"plot_minpatch(result, title = \"MinPatch Results\")"},{"path":"/articles/minpatchTasmania.html","id":"analyse-the-final-results","dir":"Articles","previous_headings":"MinPatch","what":"Analyse the final results","title":"MinPatch in Tasmania","text":"","code":"print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 58 (valid: 11) #> Final patches: 12 (valid: 11) #> Area change: 4378267698.40 (21.8%) #> #> Cost Breakdown: #> Planning unit cost: 68792497.20 #> Boundary cost: 0.00 #> Total cost: 68792497.20 #> Selected units: 427 #> #> Feature Representation: #> Total features: 33 #> Targets met: 33 #> Targets unmet: 0 #> Mean proportion: 0.449 #> Total shortfall: 0.00 #> #> #> === End Summary === # Compare original vs MinPatch solutions comparison <- compare_solutions(result) # Print overall comparison cat(\"=== Overall Solution Comparison ===\\n\") #> === Overall Solution Comparison === print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 330 427 97 29.39394 #> 2 Total Area 20052333083 24430600782 4378267698 21.83421 #> 3 Number of Patches 58 12 -46 -79.31034 #> 4 Valid Patches (>= min size) 11 11 0 0.00000 #> 5 Median Patch Size 64915437 661924221 597008784 919.67152 #> 6 Planning Unit Cost 68792497 68792497 0 0.00000 #> 7 Boundary Cost 0 0 0 NA #> 8 Total Cost 68792497 68792497 0 0.00000 # Print feature-level comparison cat(\"\\n=== Feature-Level Area Comparison ===\\n\") #> #> === Feature-Level Area Comparison === print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 1.2 2 4 2 100.000000 #> 2 2 33.0 35 39 4 11.428571 #> 3 3 2.7 3 6 3 100.000000 #> 4 4 170.1 177 197 20 11.299435 #> 5 5 213.9 221 260 39 17.647059 #> 6 6 242.1 250 317 67 26.800000 #> 7 7 9.9 12 13 1 8.333333 #> 8 8 108.3 113 137 24 21.238938 #> 9 9 30.9 41 53 12 29.268293 #> 10 10 260.4 271 339 68 25.092251 #> 11 11 62.4 67 82 15 22.388060 #> 12 12 132.0 151 190 39 25.827815 #> 13 13 133.5 138 163 25 18.115942 #> 14 14 122.4 128 137 9 7.031250 #> 15 15 62.4 66 76 10 15.151515 #> 16 16 240.0 246 310 64 26.016260 #> 17 17 0.3 1 1 0 0.000000 #> 18 18 27.6 29 29 0 0.000000 #> 19 19 6.6 8 8 0 0.000000 #> 20 20 18.0 19 25 6 31.578947 #> 21 21 24.3 31 41 10 32.258065 #> 22 22 7.5 12 13 1 8.333333 #> 23 23 34.5 39 54 15 38.461538 #> 24 24 11.1 12 12 0 0.000000 #> 25 25 47.1 51 77 26 50.980392 #> 26 26 9.3 11 11 0 0.000000 #> 27 27 86.7 88 102 14 15.909091 #> 28 28 6.6 7 12 5 71.428571 #> 29 29 1.2 2 2 0 0.000000 #> 30 30 186.0 192 195 3 1.562500 #> 31 31 66.3 71 97 26 36.619718 #> 32 32 30.9 36 49 13 36.111111 #> 33 33 57.9 60 67 7 11.666667 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.666667 #> 2 TRUE TRUE 1.060606 #> 3 TRUE TRUE 1.111111 #> 4 TRUE TRUE 1.040564 #> 5 TRUE TRUE 1.033193 #> 6 TRUE TRUE 1.032631 #> 7 TRUE TRUE 1.212121 #> 8 TRUE TRUE 1.043398 #> 9 TRUE TRUE 1.326861 #> 10 TRUE TRUE 1.040707 #> 11 TRUE TRUE 1.073718 #> 12 TRUE TRUE 1.143939 #> 13 TRUE TRUE 1.033708 #> 14 TRUE TRUE 1.045752 #> 15 TRUE TRUE 1.057692 #> 16 TRUE TRUE 1.025000 #> 17 TRUE TRUE 3.333333 #> 18 TRUE TRUE 1.050725 #> 19 TRUE TRUE 1.212121 #> 20 TRUE TRUE 1.055556 #> 21 TRUE TRUE 1.275720 #> 22 TRUE TRUE 1.600000 #> 23 TRUE TRUE 1.130435 #> 24 TRUE TRUE 1.081081 #> 25 TRUE TRUE 1.082803 #> 26 TRUE TRUE 1.182796 #> 27 TRUE TRUE 1.014994 #> 28 TRUE TRUE 1.060606 #> 29 TRUE TRUE 1.666667 #> 30 TRUE TRUE 1.032258 #> 31 TRUE TRUE 1.070890 #> 32 TRUE TRUE 1.165049 #> 33 TRUE TRUE 1.036269 #> MinPatch_Proportion #> 1 3.333333 #> 2 1.181818 #> 3 2.222222 #> 4 1.158142 #> 5 1.215521 #> 6 1.309376 #> 7 1.313131 #> 8 1.265005 #> 9 1.715210 #> 10 1.301843 #> 11 1.314103 #> 12 1.439394 #> 13 1.220974 #> 14 1.119281 #> 15 1.217949 #> 16 1.291667 #> 17 3.333333 #> 18 1.050725 #> 19 1.212121 #> 20 1.388889 #> 21 1.687243 #> 22 1.733333 #> 23 1.565217 #> 24 1.081081 #> 25 1.634820 #> 26 1.182796 #> 27 1.176471 #> 28 1.818182 #> 29 1.666667 #> 30 1.048387 #> 31 1.463047 #> 32 1.585761 #> 33 1.157168 # Print summary statistics cat(\"\\n=== Feature Change Summary ===\\n\") #> #> === Feature Change Summary === print(comparison$summary) #> features_improved features_reduced features_unchanged targets_gained #> 1 27 0 6 0 #> targets_lost #> 1 0"},{"path":"/articles/minpatchTasmania.html","id":"run-different-patch-sizes","dir":"Articles","previous_headings":"","what":"Run different patch sizes","title":"MinPatch in Tasmania","text":"minimum patch size parameter core constraint drives MinPatch behaviour - determines threshold patches considered small must either enlarged removed. Stage 1, MinPatch removes patches smaller threshold (except existing protected areas). Stage 2, adds new patches large enough meet minimum targets unmet. Stage 3 (whittling), prevents removal planning units make patch fall threshold. Larger minimum patch sizes result fewer, bigger patches potentially higher total area, MinPatch must ensure every patch meets size requirement. Smaller minimum patch sizes allow flexibility, potentially resulting patches closer original prioritizr solution. choice minimum patch size reflect ecological management considerations - example, larger patches may needed support viable populations reduce edge effects, smaller patches may acceptable highly connected landscapes features don’t require large contiguous areas.","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) min_patch_size <- median_area * 10 patch_radius <- sqrt(median_area * 10) result2 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) median_area <- median(st_area(tas)) min_patch_size <- median_area * 20 patch_radius <- sqrt(median_area * 10) result3 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE )"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution-1","dir":"Articles","previous_headings":"Run different patch sizes","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"patchwork::wrap_plots(plot_minpatch(result, title = \"Patch Size x5\"), plot_minpatch(result2, title = \"Patch Size x10\"), plot_minpatch(result3, title = \"Patch Size x20\"), guides = \"collect\", ncol = 3) & theme(legend.position = \"bottom\")"},{"path":"/articles/minpatchTasmania.html","id":"run-different-boundary-penalties","dir":"Articles","previous_headings":"","what":"Run different Boundary Penalties","title":"MinPatch in Tasmania","text":"boundary penalty controls much MinPatch prioritizes spatial compactness “simulated whittling” stage. whittling, MinPatch considers removing planning units patch edges, doesn’t increase total priortizr cost. boundary penalty affects decision penalizing fragmented solutions - higher penalties favour compact patches making costly create additional “edge” selected unselected areas. MinPatch evaluates whether remove unit, calculates change boundary length (units selected neighbours increase boundary removed, units unselected neighbours decrease boundary) multiplies boundary penalty. resulting boundary cost change exceeds unit’s cost, unit removed. datasets like Tasmania long planning unit boundaries relative unit costs, even small boundary penalties can highly influential, potentially preventing unit removals resulting similar solutions across different penalty values. small penalties (e.g., 1e-10) may needed see meaningful differences cases.","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) min_patch_size <- median_area * 5 patch_radius <- sqrt(median_area * 10) result4 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 1e-5, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) result5 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 1e-10, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE )"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution-2","dir":"Articles","previous_headings":"Run different Boundary Penalties","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"patchwork::wrap_plots(plot_minpatch(result, title = \"Boundary Penalty: 0\"), plot_minpatch(result4, title = \"Boundary Penalty: 1e-5\"), plot_minpatch(result5, title = \"Boundary Penalty: 1e-10\"), guides = \"collect\", ncol = 3) & theme(legend.position = \"bottom\")"},{"path":"/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Jason D. Everett. Author, maintainer. Anthony J. Richardson. Author. Robert J. Smith. Author. Original MinPatch algorithm author","code":""},{"path":"/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Everett J, Richardson , Smith R (2025). minpatch: Post-Processing Conservation Planning Solutions Ensure Minimum Patch Sizes. R package version 0.1.0, https://github.com/SpatialPlanning/minpatch.","code":"@Manual{, title = {minpatch: Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes}, author = {Jason D. Everett and Anthony J. Richardson and Robert J. Smith}, year = {2025}, note = {R package version 0.1.0}, url = {https://github.com/SpatialPlanning/minpatch}, }"},{"path":"/index.html","id":"minpatch-for-r","dir":"","previous_headings":"","what":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Note: still work progress significant bugs may present. Use caution information original implemention MinPatch Marxan QGIS available : https://cluz-systematic-conservation-planning.github.io","code":""},{"path":"/index.html","id":"overview","dir":"","previous_headings":"","what":"Overview","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"R implementation MinPatch algorithm post-processing conservation planning solutions ensure minimum protected area sizes. MinPatch post-processing tool conservation planning solutions ensures protected areas meet user-defined minimum size thresholds. R package implements methodology described Smith et al. (2010) designed work solutions prioritizr package, though can work binary conservation solution.","code":""},{"path":"/index.html","id":"the-problem","dir":"","previous_headings":"Overview","what":"The Problem","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Conservation planning software like Marxan prioritizr can produce solutions many small, fragmented protected areas. solutions may mathematically optimal, small protected areas often: Less ecologically viable expensive manage vulnerable edge effects Less resilient disturbances","code":""},{"path":"/index.html","id":"the-solution","dir":"","previous_headings":"Overview","what":"The Solution","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"MinPatch addresses post-processing conservation solutions three stages: Remove Small Patches: Eliminate protected areas smaller minimum size threshold Add New Patches: Add new areas meet conservation targets using BestPatch algorithm Simulated Whittling: Remove unnecessary planning units maintaining constraints","code":""},{"path":"/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"","code":"# Install from GitHub pak::pak(\"SpatialPlanning/minpatch\")"},{"path":"/index.html","id":"key-features","dir":"","previous_headings":"","what":"Key Features","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Full MinPatch Algorithm: Complete implementation three stages prioritizr Integration: Seamless workflow prioritizr solutions Flexible Parameters: Control minimum patch sizes, patch radius, boundary penalties Comprehensive Reporting: Detailed statistics comparisons Visualization Support: Plot results ggplot2 (optional)","code":""},{"path":[]},{"path":"/index.html","id":"stage-1-remove-small-patches","dir":"","previous_headings":"Algorithm Details","what":"Stage 1: Remove Small Patches","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Identifies connected components (patches) solution removes smaller minimum size threshold. removes patches weren’t originally designated conserved areas.","code":""},{"path":"/index.html","id":"stage-2-add-new-patches-bestpatch-algorithm","dir":"","previous_headings":"Algorithm Details","what":"Stage 2: Add New Patches (BestPatch Algorithm)","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Uses BestPatch scoring system add new patches: Calculate current conservation levels feature Identify features unmet targets Score potential patches based contribution targets relative cost Add highest-scoring patch repeat BestPatch score calculated :","code":"Score = Σ(feature_contribution / target_gap) / patch_cost"},{"path":"/index.html","id":"stage-3-simulated-whittling","dir":"","previous_headings":"Algorithm Details","what":"Stage 3: Simulated Whittling","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Removes unnecessary planning units iterative process: Identify edge units (boundary selected areas) Calculate whittling scores based feature importance Must cause targets unmet Must make patches small Must increase total cost (boundary penalty > 0) Must split patches non-viable pieces","code":""},{"path":"/index.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"use package, please cite original paper implementation:","code":"Smith, R.J., Di Minin, E., Linke, S., Segan, D.B., Possingham, H.P. (2010). An approach for ensuring minimum protected area size in systematic conservation planning. Biological Conservation, 143(10), 2525-2531. Everett J.D., Richardson A.J., Smith R.J. (2025). _minpatch: Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes_. R package version 0.1.0, ."},{"path":"/index.html","id":"license","dir":"","previous_headings":"","what":"License","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"GPL (>= 3)","code":""},{"path":"/index.html","id":"references","dir":"","previous_headings":"","what":"References","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Smith, R.J., Di Minin, E., Linke, S., Segan, D.B., Possingham, H.P. (2010). approach ensuring minimum protected area size systematic conservation planning. Biological Conservation, 143(10), 2525-2531.","code":""},{"path":"/index.html","id":"getting-help","dir":"","previous_headings":"","what":"Getting Help","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Check package vignette: vignette(\"minpatch\") View function documentation: ?run_minpatch Report bugs: GitHub Issues","code":""},{"path":"/reference/add_new_patches.html","id":null,"dir":"Reference","previous_headings":"","what":"Add new patches to meet conservation targets — add_new_patches","title":"Add new patches to meet conservation targets — add_new_patches","text":"Stage 2 MinPatch: Add new patches using BestPatch algorithm","code":""},{"path":"/reference/add_new_patches.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add new patches to meet conservation targets — add_new_patches","text":"","code":"add_new_patches(minpatch_data, verbose = TRUE)"},{"path":"/reference/add_new_patches.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add new patches to meet conservation targets — add_new_patches","text":"minpatch_data List containing MinPatch data structures (including prioritizr objects) verbose Logical, whether print progress","code":""},{"path":"/reference/add_new_patches.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add new patches to meet conservation targets — add_new_patches","text":"Updated minpatch_data new patches added","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":null,"dir":"Reference","previous_headings":"","what":"Add patch centered on specified planning unit — add_patch_centered_on_unit","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"Add patch centered specified planning unit","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"","code":"add_patch_centered_on_unit(minpatch_data, center_unit_id)"},{"path":"/reference/add_patch_centered_on_unit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"minpatch_data List containing MinPatch data structures center_unit_id ID unit center patch ","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"Updated unit_dict new patch added","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"Implements BestPatch scoring algorithm original paper","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"","code":"calculate_best_patch_scores(minpatch_data, feature_amounts, unmet_targets)"},{"path":"/reference/calculate_best_patch_scores.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"minpatch_data List containing MinPatch data structures feature_amounts Named vector current conservation amounts unmet_targets Character vector features unmet targets","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"Named vector BestPatch scores","code":""},{"path":"/reference/calculate_cost_summary.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"Calculates various cost components using prioritizr functions possible","code":""},{"path":"/reference/calculate_cost_summary.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"","code":"calculate_cost_summary(minpatch_data)"},{"path":"/reference/calculate_cost_summary.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_cost_summary.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"List containing detailed cost breakdown","code":""},{"path":"/reference/calculate_feature_conservation.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate current feature conservation amounts — calculate_feature_conservation","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"Calculates much feature currently conserved","code":""},{"path":"/reference/calculate_feature_conservation.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"","code":"calculate_feature_conservation(minpatch_data)"},{"path":"/reference/calculate_feature_conservation.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_feature_conservation.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"Named vector conserved amounts feature","code":""},{"path":"/reference/calculate_feature_representation.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate feature representation in solution — calculate_feature_representation","title":"Calculate feature representation in solution — calculate_feature_representation","text":"Calculates much conservation feature represented current solution using prioritizr functions possible","code":""},{"path":"/reference/calculate_feature_representation.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate feature representation in solution — calculate_feature_representation","text":"","code":"calculate_feature_representation(minpatch_data)"},{"path":"/reference/calculate_feature_representation.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate feature representation in solution — calculate_feature_representation","text":"minpatch_data List containing MinPatch data structures including prioritizr objects","code":""},{"path":"/reference/calculate_feature_representation.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate feature representation in solution — calculate_feature_representation","text":"Data frame feature representation statistics","code":""},{"path":"/reference/calculate_patch_stats.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate patch statistics — calculate_patch_stats","title":"Calculate patch statistics — calculate_patch_stats","text":"Calculates summary statistics patches including areas counts","code":""},{"path":"/reference/calculate_patch_stats.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate patch statistics — calculate_patch_stats","text":"","code":"calculate_patch_stats(minpatch_data)"},{"path":"/reference/calculate_patch_stats.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate patch statistics — calculate_patch_stats","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_patch_stats.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate patch statistics — calculate_patch_stats","text":"Updated minpatch_data patch statistics added","code":""},{"path":"/reference/calculate_whittle_scores.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate whittling scores for edge units — calculate_whittle_scores","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"Calculates \"Low Relevance\" score edge unit based feature importance (Equation A2 original paper)","code":""},{"path":"/reference/calculate_whittle_scores.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"","code":"calculate_whittle_scores(edge_units, minpatch_data)"},{"path":"/reference/calculate_whittle_scores.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"edge_units Character vector edge unit IDs minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_whittle_scores.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"Named vector whittling scores","code":""},{"path":"/reference/can_remove_unit.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if a planning unit can be removed — can_remove_unit","title":"Check if a planning unit can be removed — can_remove_unit","text":"Checks multiple criteria determine removing unit acceptable: 1. violate conservation targets 2. make patch small 3. increase total cost 4. split patches non-viable pieces","code":""},{"path":"/reference/can_remove_unit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if a planning unit can be removed — can_remove_unit","text":"","code":"can_remove_unit(unit_id, minpatch_data)"},{"path":"/reference/can_remove_unit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if a planning unit can be removed — can_remove_unit","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/can_remove_unit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if a planning unit can be removed — can_remove_unit","text":"Logical indicating unit can removed","code":""},{"path":"/reference/compare_solutions.html","id":null,"dir":"Reference","previous_headings":"","what":"Compare solutions before and after MinPatch — compare_solutions","title":"Compare solutions before and after MinPatch — compare_solutions","text":"Creates comprehensive comparison key metrics original MinPatch solutions, including overall statistics detailed feature-level analysis","code":""},{"path":"/reference/compare_solutions.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Compare solutions before and after MinPatch — compare_solutions","text":"","code":"compare_solutions(minpatch_result)"},{"path":"/reference/compare_solutions.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Compare solutions before and after MinPatch — compare_solutions","text":"minpatch_result Result run_minpatch function","code":""},{"path":"/reference/compare_solutions.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Compare solutions before and after MinPatch — compare_solutions","text":"List containing: overall: Data frame overall solution comparison features: Data frame feature-level area comparisons summary: List summary statistics feature changes","code":""},{"path":"/reference/compare_solutions.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Compare solutions before and after MinPatch — compare_solutions","text":"","code":"library(prioritizr) library(sf) #> Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE library(terra) #> terra 1.8.80 # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) # Compare solutions comparison <- compare_solutions(result) # Print overall comparison print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.000 21.000 5.000 31.25000 #> 2 Total Area 0.160 0.210 0.050 31.25000 #> 3 Number of Patches 7.000 4.000 -3.000 -42.85714 #> 4 Valid Patches (>= min size) 1.000 2.000 1.000 100.00000 #> 5 Median Patch Size 0.010 0.055 0.045 450.00000 #> 6 Planning Unit Cost 4137.804 4137.804 0.000 0.00000 #> 7 Boundary Cost 0.000 0.000 0.000 NA #> 8 Total Cost 4137.804 4137.804 0.000 0.00000 # Print feature-level comparison print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 18.554865 4.4714362 31.74963 #> 2 2 4.774965 5.124808 6.090809 0.9660007 18.84950 #> 3 3 11.029225 11.707674 15.121749 3.4140748 29.16100 #> 4 4 6.489033 6.863962 8.676751 1.8127892 26.41025 #> 5 5 8.613574 9.482534 12.907049 3.4245152 36.11393 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.464447 #> 2 1.275571 #> 3 1.371062 #> 4 1.337141 #> 5 1.498455 # Print summary statistics cat(\"Features improved:\", comparison$summary$features_improved, \"\\n\") #> Features improved: 5 cat(\"Targets gained:\", comparison$summary$targets_gained, \"\\n\") #> Targets gained: 0"},{"path":"/reference/create_abundance_matrix.html","id":null,"dir":"Reference","previous_headings":"","what":"Create abundance matrix from planning units — create_abundance_matrix","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"Creates matrix showing amount feature planning unit extracting feature columns directly planning_units using prioritizr problem","code":""},{"path":"/reference/create_abundance_matrix.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"","code":"create_abundance_matrix(planning_units, prioritizr_problem)"},{"path":"/reference/create_abundance_matrix.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"planning_units sf object planning unit geometries feature columns prioritizr_problem prioritizr problem object get feature names","code":""},{"path":"/reference/create_abundance_matrix.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"Named list planning unit contains feature abundances","code":""},{"path":"/reference/create_boundary_matrix.html","id":null,"dir":"Reference","previous_headings":"","what":"Create boundary matrix from planning units — create_boundary_matrix","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"Creates matrix shared boundary lengths adjacent planning units","code":""},{"path":"/reference/create_boundary_matrix.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"","code":"create_boundary_matrix(planning_units, verbose = TRUE)"},{"path":"/reference/create_boundary_matrix.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"planning_units sf object planning unit geometries","code":""},{"path":"/reference/create_boundary_matrix.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"Named list element contains neighbors shared boundary lengths","code":""},{"path":"/reference/create_patch_radius_dict.html","id":null,"dir":"Reference","previous_headings":"","what":"Create patch radius dictionary — create_patch_radius_dict","title":"Create patch radius dictionary — create_patch_radius_dict","text":"planning unit, find units within specified patch radius","code":""},{"path":"/reference/create_patch_radius_dict.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create patch radius dictionary — create_patch_radius_dict","text":"","code":"create_patch_radius_dict(planning_units, patch_radius, verbose = TRUE)"},{"path":"/reference/create_patch_radius_dict.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create patch radius dictionary — create_patch_radius_dict","text":"planning_units sf object planning unit geometries patch_radius radius patch creation","code":""},{"path":"/reference/create_patch_radius_dict.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create patch radius dictionary — create_patch_radius_dict","text":"Named list planning unit contains list units within radius","code":""},{"path":"/reference/create_solution_vector.html","id":null,"dir":"Reference","previous_headings":"","what":"Create solution vector from unit dictionary — create_solution_vector","title":"Create solution vector from unit dictionary — create_solution_vector","text":"Converts internal unit dictionary back binary solution vector","code":""},{"path":"/reference/create_solution_vector.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create solution vector from unit dictionary — create_solution_vector","text":"","code":"create_solution_vector(unit_dict)"},{"path":"/reference/create_solution_vector.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create solution vector from unit dictionary — create_solution_vector","text":"unit_dict Named list containing cost status planning unit","code":""},{"path":"/reference/create_solution_vector.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create solution vector from unit dictionary — create_solution_vector","text":"Binary numeric vector indicating selected planning units","code":""},{"path":"/reference/find_edge_units.html","id":null,"dir":"Reference","previous_headings":"","what":"Find edge planning units — find_edge_units","title":"Find edge planning units — find_edge_units","text":"Identifies planning units edge selected areas (least one unselected neighbor)","code":""},{"path":"/reference/find_edge_units.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find edge planning units — find_edge_units","text":"","code":"find_edge_units(minpatch_data)"},{"path":"/reference/find_edge_units.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find edge planning units — find_edge_units","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/find_edge_units.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find edge planning units — find_edge_units","text":"Character vector edge unit IDs","code":""},{"path":"/reference/generate_minpatch_report.html","id":null,"dir":"Reference","previous_headings":"","what":"Generate comprehensive MinPatch report — generate_minpatch_report","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"Creates detailed report MinPatch processing results","code":""},{"path":"/reference/generate_minpatch_report.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"","code":"generate_minpatch_report(minpatch_result)"},{"path":"/reference/generate_minpatch_report.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"minpatch_result Result object run_minpatch function","code":""},{"path":"/reference/generate_minpatch_report.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"List containing formatted report components","code":""},{"path":"/reference/generate_minpatch_report.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) generate_minpatch_report(result) #> $features #> # A tibble: 5 × 9 #> feature met total_amount absolute_target absolute_held absolute_shortfall #> #> 1 feature_1 TRUE 74.5 12.7 18.6 0 #> 2 feature_2 TRUE 28.1 4.77 6.09 0 #> 3 feature_3 TRUE 64.9 11.0 15.1 0 #> 4 feature_4 TRUE 38.2 6.49 8.68 0 #> 5 feature_5 TRUE 50.7 8.61 12.9 0 #> # ℹ 3 more variables: relative_target , relative_held , #> # relative_shortfall #> #> $patch_stats #> time all_patch_count all_patch_area median_all_patch valid_patch_count #> 1 initial 7 0.16 0.010 1 #> 2 final 4 0.21 0.055 2 #> valid_patch_area median_valid_patch #> 1 0.05 0.050 #> 2 0.15 0.075 #> #> $cost #> # A tibble: 1 × 6 #> summary cost n boundary_length boundary_cost total_cost #> #> 1 overall 4138. 21 0 0 4138. #>"},{"path":"/reference/identify_unmet_targets.html","id":null,"dir":"Reference","previous_headings":"","what":"Identify features with unmet targets — identify_unmet_targets","title":"Identify features with unmet targets — identify_unmet_targets","text":"Uses prioritizr functions identify unmet targets minpatch_data","code":""},{"path":"/reference/identify_unmet_targets.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Identify features with unmet targets — identify_unmet_targets","text":"","code":"identify_unmet_targets(minpatch_data)"},{"path":"/reference/identify_unmet_targets.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Identify features with unmet targets — identify_unmet_targets","text":"minpatch_data List containing MinPatch data structures including prioritizr objects","code":""},{"path":"/reference/identify_unmet_targets.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Identify features with unmet targets — identify_unmet_targets","text":"Character vector feature IDs unmet targets","code":""},{"path":"/reference/initialize_minpatch_data.html","id":null,"dir":"Reference","previous_headings":"","what":"Initialize MinPatch data structures — initialize_minpatch_data","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"Creates internal data structures needed MinPatch processing","code":""},{"path":"/reference/initialize_minpatch_data.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"","code":"initialize_minpatch_data( solution, planning_units, targets, costs, min_patch_size, patch_radius, boundary_penalty, prioritizr_problem, prioritizr_solution, verbose = TRUE )"},{"path":"/reference/initialize_minpatch_data.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"solution Binary solution vector planning_units sf object planning units targets data.frame targets costs numeric vector costs min_patch_size minimum patch size patch_radius patch radius boundary_penalty Boundary penalty value prioritizr_problem prioritizr problem object prioritizr_solution solved prioritizr solution object","code":""},{"path":"/reference/initialize_minpatch_data.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"List containing necessary data structures","code":""},{"path":"/reference/make_patch_dict.html","id":null,"dir":"Reference","previous_headings":"","what":"Create patch dictionary from unit dictionary — make_patch_dict","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"Identifies connected components (patches) current solution","code":""},{"path":"/reference/make_patch_dict.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"","code":"make_patch_dict(minpatch_data)"},{"path":"/reference/make_patch_dict.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/make_patch_dict.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"Named list patch contains area, unit count, unit IDs","code":""},{"path":"/reference/minpatch-package.html","id":null,"dir":"Reference","previous_headings":"","what":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","title":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","text":"package provides functions post-process conservation planning solutions prioritizr ensure protected areas meet user-defined minimum size thresholds, following methodology described Smith et al. (2010).","code":""},{"path":[]},{"path":"/reference/minpatch-package.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","text":"Maintainer: Jason D. Everett DrJasonEverett@gmail.com (ORCID) Authors: Anthony J. Richardson .richardson1@uq.edu.au (ORCID) Robert J. Smith (Original MinPatch algorithm author)","code":""},{"path":"/reference/pipe.html","id":null,"dir":"Reference","previous_headings":"","what":"Pipe operator — %>%","title":"Pipe operator — %>%","text":"See magrittr::%>% details.","code":""},{"path":"/reference/pipe.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Pipe operator — %>%","text":"","code":"lhs %>% rhs"},{"path":"/reference/pipe.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Pipe operator — %>%","text":"lhs value magrittr placeholder. rhs function call using magrittr semantics.","code":""},{"path":"/reference/pipe.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Pipe operator — %>%","text":"result calling `rhs(lhs)`.","code":""},{"path":"/reference/plot_minpatch.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize MinPatch results — plot_minpatch","title":"Visualize MinPatch results — plot_minpatch","text":"Creates simple visualization MinPatch results showing original vs. modified solutions","code":""},{"path":"/reference/plot_minpatch.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"plot_minpatch(minpatch_result, title = \"MinPatch Results\")"},{"path":"/reference/plot_minpatch.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize MinPatch results — plot_minpatch","text":"minpatch_result Result run_minpatch function title Plot title (optional)","code":""},{"path":"/reference/plot_minpatch.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize MinPatch results — plot_minpatch","text":"ggplot object (ggplot2 available)","code":""},{"path":"/reference/plot_minpatch.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) # Visualize results plot_minpatch(result)"},{"path":"/reference/plot_prioritizr.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize prioritizr solutions — plot_prioritizr","title":"Visualize prioritizr solutions — plot_prioritizr","text":"Creates simple visualization prioritizr solutions showing selected unselected planning units using ggplot2","code":""},{"path":"/reference/plot_prioritizr.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize prioritizr solutions — plot_prioritizr","text":"","code":"plot_prioritizr(s, col = \"solution_1\", title = \"prioritizr Solution\")"},{"path":"/reference/plot_prioritizr.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize prioritizr solutions — plot_prioritizr","text":"s sf object containing planning units solution data col Column name containing solution values (default = \"solution_1\") title Plot title (default = \"prioritizr Solution\")","code":""},{"path":"/reference/plot_prioritizr.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize prioritizr solutions — plot_prioritizr","text":"ggplot object showing spatial solution","code":""},{"path":"/reference/plot_prioritizr.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize prioritizr solutions — plot_prioritizr","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Plot the solution plot_prioritizr(s) # Plot with custom title and column plot_prioritizr(s, col = \"solution_1\", title = \"My Conservation Plan\")"},{"path":"/reference/print_minpatch_summary.html","id":null,"dir":"Reference","previous_headings":"","what":"Print MinPatch results summary — print_minpatch_summary","title":"Print MinPatch results summary — print_minpatch_summary","text":"Prints formatted summary MinPatch processing results","code":""},{"path":"/reference/print_minpatch_summary.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Print MinPatch results summary — print_minpatch_summary","text":"","code":"print_minpatch_summary(minpatch_result)"},{"path":"/reference/print_minpatch_summary.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Print MinPatch results summary — print_minpatch_summary","text":"minpatch_result Result object run_minpatch function","code":""},{"path":"/reference/print_minpatch_summary.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Print MinPatch results summary — print_minpatch_summary","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002500108 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 4 #> Found 76 potential patches with scores #> Best score: 0.002060928 for unit 78 #> Added patch centered on unit 78 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 21 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 21 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 20 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 20 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 19 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 19 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 18 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 18 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 17 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 17 #> Unit 73 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 72 cannot be removed - adding to keystone set #> Unit 88 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> Unit 64 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete! print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 1) #> Final patches: 4 (valid: 2) #> Area change: 0.05 (31.2%) #> #> Cost Breakdown: #> Planning unit cost: 4137.80 #> Boundary cost: 0.00 #> Total cost: 4137.80 #> Selected units: 21 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.236 #> Total shortfall: 0.00 #> #> #> === End Summary ==="},{"path":"/reference/removal_increases_cost.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would increase cost — removal_increases_cost","title":"Check if removing unit would increase cost — removal_increases_cost","text":"Check removing unit increase cost","code":""},{"path":"/reference/removal_increases_cost.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would increase cost — removal_increases_cost","text":"","code":"removal_increases_cost(unit_id, minpatch_data)"},{"path":"/reference/removal_increases_cost.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would increase cost — removal_increases_cost","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_increases_cost.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would increase cost — removal_increases_cost","text":"Logical indicating removal increase cost","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"Check removing unit increase Marxan cost","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"","code":"removal_increases_marxan_cost(unit_id, minpatch_data)"},{"path":"/reference/removal_increases_marxan_cost.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"Logical indicating removal increase cost","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"Check removing unit make patch small","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"","code":"removal_makes_patch_too_small(unit_id, minpatch_data)"},{"path":"/reference/removal_makes_patch_too_small.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"Logical indicating removal make patch small","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"Check removing unit split patch non-viable pieces","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"","code":"removal_splits_patch_nonviably(unit_id, minpatch_data)"},{"path":"/reference/removal_splits_patch_nonviably.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"Logical indicating removal create non-viable patches","code":""},{"path":"/reference/removal_violates_targets.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would violate conservation targets — removal_violates_targets","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"Check removing unit violate conservation targets","code":""},{"path":"/reference/removal_violates_targets.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"","code":"removal_violates_targets(unit_id, minpatch_data)"},{"path":"/reference/removal_violates_targets.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_violates_targets.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"Logical indicating removal violate targets","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":null,"dir":"Reference","previous_headings":"","what":"Remove small patches from solution — remove_small_patches_from_solution","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"Stage 1 MinPatch: Remove patches smaller minimum size threshold","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"","code":"remove_small_patches_from_solution(minpatch_data)"},{"path":"/reference/remove_small_patches_from_solution.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"Updated minpatch_data small patches removed","code":""},{"path":"/reference/run_minpatch.html","id":null,"dir":"Reference","previous_headings":"","what":"Run MinPatch algorithm on prioritizr solution — run_minpatch","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"main function applies MinPatch algorithm prioritizr solution ensure protected areas meet minimum size thresholds. function uses prioritizr summary functions possible reduce code duplication ensure consistency prioritizr calculations.","code":""},{"path":"/reference/run_minpatch.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"","code":"run_minpatch( prioritizr_problem, prioritizr_solution, min_patch_size, patch_radius, boundary_penalty = 0, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, solution_column = \"solution_1\", verbose = TRUE )"},{"path":"/reference/run_minpatch.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"prioritizr_problem prioritizr problem object prioritizr_solution solved prioritizr solution object min_patch_size Minimum patch size threshold patch_radius Radius adding new patches boundary_penalty Boundary penalty value (default = 0) remove_small_patches Logical, whether remove small patches (Stage 1, default = TRUE) add_patches Logical, whether add new patches meet targets (Stage 2, default = TRUE) whittle_patches Logical, whether remove unnecessary units (Stage 3, default = TRUE) solution_column Name solution column (default = \"solution_1\") verbose Logical, whether print progress (default = TRUE)","code":""},{"path":"/reference/run_minpatch.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"MinPatch result object enhanced reporting using prioritizr functions","code":""},{"path":"/reference/run_minpatch.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"MinPatch algorithm consists three stages: Remove small patches: Removes patches smaller min_patch_size Add new patches: Adds patches meet conservation targets Whittle patches: Removes unnecessary planning units **Important**: set remove_small_patches = TRUE add_patches = FALSE, algorithm may remove patches without compensating, potentially violating conservation targets. cases, warning issued. Consider using add_patches = TRUE smaller min_patch_size maintain target achievement.","code":""},{"path":"/reference/run_minpatch.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Apply MinPatch with all stages result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002500108 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 4 #> Found 76 potential patches with scores #> Best score: 0.002060928 for unit 78 #> Added patch centered on unit 78 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 21 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 21 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 20 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 20 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 19 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 19 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 18 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 18 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 17 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 17 #> Unit 73 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 72 cannot be removed - adding to keystone set #> Unit 88 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> Unit 64 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete! # Apply MinPatch with only Stage 1 and 3 (skip adding patches) result2 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, add_patches = FALSE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Warning: After removing small patches, 5 conservation targets are no longer met. Consider setting add_patches = TRUE to automatically add patches to meet targets, or use a smaller min_patch_size. #> Warning: 5 targets are no longer met after removing small patches #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Stage 2: Skipping addition of new patches... #> Stage 3: Removing unnecessary planning units... #> Edge units found: 5 #> Keystone units: 0 #> New keystone units: 5 #> Scoreable units: 0 #> No units can be removed - all are keystone - terminating #> Calculating final statistics... #> MinPatch processing complete! print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 1) #> Final patches: 4 (valid: 2) #> Area change: 0.05 (31.2%) #> #> Cost Breakdown: #> Planning unit cost: 4137.80 #> Boundary cost: 0.00 #> Total cost: 4137.80 #> Selected units: 21 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.236 #> Total shortfall: 0.00 #> #> #> === End Summary ==="},{"path":"/reference/simulated_whittling.html","id":null,"dir":"Reference","previous_headings":"","what":"Simulated whittling to remove unnecessary planning units — simulated_whittling","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"Stage 3 MinPatch: Remove planning units needed meet targets, reduce fragmentation, meet minimum patch size requirements","code":""},{"path":"/reference/simulated_whittling.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"","code":"simulated_whittling(minpatch_data, verbose = TRUE)"},{"path":"/reference/simulated_whittling.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"minpatch_data List containing MinPatch data structures (including prioritizr objects) verbose Logical, whether print progress","code":""},{"path":"/reference/simulated_whittling.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"Updated minpatch_data unnecessary units removed","code":""},{"path":"/reference/validate_inputs.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate MinPatch inputs — validate_inputs","title":"Validate MinPatch inputs — validate_inputs","text":"Internal function validate inputs MinPatch algorithm","code":""},{"path":"/reference/validate_inputs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate MinPatch inputs — validate_inputs","text":"","code":"validate_inputs( solution, planning_units, targets, costs, min_patch_size, patch_radius, boundary_penalty )"},{"path":"/reference/validate_inputs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate MinPatch inputs — validate_inputs","text":"solution Binary solution vector planning_units sf object planning units targets data.frame targets costs numeric vector costs min_patch_size minimum patch size patch_radius patch radius adding patches boundary_penalty Boundary penalty value","code":""},{"path":"/reference/validate_inputs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate MinPatch inputs — validate_inputs","text":"NULL (throws errors validation fails)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize MinPatch results — plot_minpatch","title":"Visualize MinPatch results — plot_minpatch","text":"Creates simple visualization MinPatch results showing original vs. modified solutions","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"plot_minpatch(minpatch_result, title = \"MinPatch Results\")"},{"path":"/reference/visualize_minpatch_results.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize MinPatch results — plot_minpatch","text":"minpatch_result Result run_minpatch function title Plot title (optional)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize MinPatch results — plot_minpatch","text":"ggplot object (ggplot2 available)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"if (FALSE) { # \\dontrun{ # Requires ggplot2 library(ggplot2) # Create example data example_data <- create_example_data(n_units = 25, n_features = 3) # Create prioritizr problem and solve library(prioritizr) p <- problem(example_data$planning_units, cost_column = \"cost\") %>% add_min_set_objective() %>% add_manual_targets(example_data$targets) %>% add_binary_decisions() s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 2.0, patch_radius = 1.5 ) # Visualize results plot <- plot_minpatch(result) print(plot) } # }"}] +[{"path":"/articles/minpatch.html","id":"introduction","dir":"Articles","previous_headings":"","what":"Introduction","title":"MinPatch with prioritizr","text":"vignette demonstrates use MinPatch real conservation planning data prioritizr. ’ll use simulated dataset included prioritizr show complete workflow problem formulation MinPatch post-processing.","code":"library(minpatch) library(prioritizr) library(sf) library(terra) library(dplyr) library(ggplot2) library(patchwork)"},{"path":"/articles/minpatch.html","id":"step-1-load-and-examine-the-data","dir":"Articles","previous_headings":"Introduction","what":"Step 1: Load and Examine the Data","title":"MinPatch with prioritizr","text":"","code":"dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\")"},{"path":"/articles/minpatch.html","id":"step-2-create-and-solve-a-prioritizr-problem","dir":"Articles","previous_headings":"Introduction","what":"Step 2: Create and Solve a prioritizr Problem","title":"MinPatch with prioritizr","text":"’ll create simple minimum set problem 17% targets features:","code":"# Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve the problem s <- solve(p) # plot map of prioritization plot_prioritizr(s)"},{"path":"/articles/minpatch.html","id":"step-3-run-minpatch","dir":"Articles","previous_headings":"Introduction","what":"Step 3: Run MinPatch","title":"MinPatch with prioritizr","text":"Now can apply MinPatch directly prioritizr objects. run_minpatch() function automatically extracts necessary data prioritizr solution object: Run MinPatch automatic data extraction prioritizr objects","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(dat)) # Set minimum patch size to 5x median planning unit area min_patch_size <- median_area * 5 # Set patch radius to encompass approximately 10 planning units patch_radius <- sqrt(median_area * 10) cat(\"MinPatch parameters:\\n\") #> MinPatch parameters: cat(\"- Minimum patch size:\", round(min_patch_size, 3), \"square meters\\n\") #> - Minimum patch size: 0.05 square meters cat(\"- Patch radius:\", round(patch_radius,3), \"meters\\n\") #> - Patch radius: 0.316 meters cat(\"- This means patches must be at least\", round(min_patch_size/median_area, 3), \"times the median planning unit size\\n\") #> - This means patches must be at least 5 times the median planning unit size result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 0.001, # Small boundary penalty for connectivity remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = TRUE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002280652 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 2 #> Found 74 potential patches with scores #> Best score: 0.0009039778 for unit 86 #> Added patch centered on unit 86 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 27 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 27 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 26 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 26 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 25 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 25 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 24 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 24 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 23 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 23 #> Unit 88 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 75 cannot be removed - adding to keystone set #> Unit 83 cannot be removed - adding to keystone set #> Unit 73 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete!"},{"path":"/articles/minpatch.html","id":"step-4-analyze-the-results","dir":"Articles","previous_headings":"Introduction","what":"Step 4: Analyze the Results","title":"MinPatch with prioritizr","text":"Let’s examine MinPatch accomplished:","code":"# Print comprehensive summary print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 0) #> Final patches: 6 (valid: 2) #> Area change: 0.11 (68.7%) #> #> Cost Breakdown: #> Planning unit cost: 5353.26 #> Boundary cost: 0.00 #> Total cost: 5353.26 #> Selected units: 27 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.304 #> Total shortfall: 0.00 #> #> #> === End Summary === # Compare original vs MinPatch solutions comparison <- compare_solutions(result) # Print overall comparison cat(\"=== Overall Solution Comparison ===\\n\") #> === Overall Solution Comparison === print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.00000 27.00000 11.00 68.75000 #> 2 Total Area 0.16000 0.27000 0.11 68.75000 #> 3 Number of Patches 7.00000 6.00000 -1.00 -14.28571 #> 4 Valid Patches (>= min size) 0.00000 2.00000 2.00 NA #> 5 Median Patch Size 0.01000 0.04000 0.03 300.00000 #> 6 Planning Unit Cost 5353.25938 5353.25938 0.00 0.00000 #> 7 Boundary Cost 0.00395 0.00395 0.00 0.00000 #> 8 Total Cost 5353.26333 5353.26333 0.00 0.00000 # Print feature-level comparison cat(\"\\n=== Feature-Level Area Comparison ===\\n\") #> #> === Feature-Level Area Comparison === print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 24.037947 9.954517 70.68248 #> 2 2 4.774965 5.124808 7.812367 2.687559 52.44214 #> 3 3 11.029225 11.707674 19.594225 7.886551 67.36224 #> 4 4 6.489033 6.863962 10.995588 4.131626 60.19302 #> 5 5 8.613574 9.482534 16.665588 7.183054 75.75037 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.897200 #> 2 1.636110 #> 3 1.776573 #> 4 1.694488 #> 5 1.934805 # Print summary statistics cat(\"\\n=== Feature Change Summary ===\\n\") #> #> === Feature Change Summary === print(comparison$summary) #> features_improved features_reduced features_unchanged targets_gained #> 1 5 0 0 0 #> targets_lost #> 1 0 # cat(\"Features with increased area:\", comparison$summary$features_improved, \"\\n\") # cat(\"Features with decreased area:\", comparison$summary$features_reduced, \"\\n\") # cat(\"Features with unchanged area:\", comparison$summary$features_unchanged, \"\\n\") # cat(\"Targets gained:\", comparison$summary$targets_gained, \"\\n\") # cat(\"Targets lost:\", comparison$summary$targets_lost, \"\\n\")"},{"path":"/articles/minpatch.html","id":"feature-representation-analysis","dir":"Articles","previous_headings":"Introduction > Step 4: Analyze the Results","what":"Feature Representation Analysis","title":"MinPatch with prioritizr","text":"","code":"# Create solution data for prioritizr analysis minpatch_solution_data <- result$solution[c(\"minpatch\")] # Use prioritizr functions for accurate feature representation analysis feature_rep <- prioritizr::eval_feature_representation_summary(p, minpatch_solution_data) target_coverage <- prioritizr::eval_target_coverage_summary(p, minpatch_solution_data) # Summary statistics targets_met <- sum(target_coverage$met) mean_achievement <- mean(feature_rep$relative_held, na.rm = TRUE) cat(\"Conservation Performance:\\n\") #> Conservation Performance: cat(\"- Targets met:\", targets_met, \"out of\", nrow(feature_rep), \"features\\n\") #> - Targets met: 5 out of 5 features cat(\"- Mean target achievement:\", round(mean_achievement * 100, 1), \"%\\n\") #> - Mean target achievement: 30.4 % # Show features with lowest achievement combined_results <- data.frame( feature_id = seq_len(nrow(feature_rep)), proportion_met = feature_rep$relative_held, target_met = target_coverage$met ) worst_features <- combined_results[order(combined_results$proportion_met), ][1:5, ] cat(\"\\nFeatures with lowest target achievement:\\n\") #> #> Features with lowest target achievement: print(worst_features) #> feature_id proportion_met target_met #> 2 2 0.2781387 TRUE #> 4 4 0.2880629 TRUE #> 3 3 0.3020174 TRUE #> 1 1 0.3225241 TRUE #> 5 5 0.3289169 TRUE"},{"path":"/articles/minpatch.html","id":"spatial-configuration-improvements","dir":"Articles","previous_headings":"Introduction > Step 4: Analyze the Results","what":"Spatial Configuration Improvements","title":"MinPatch with prioritizr","text":"","code":"initial_stats <- result$patch_stats$initial final_stats <- result$patch_stats$final cat(\"Spatial Configuration Changes:\\n\") #> Spatial Configuration Changes: cat(\"- Initial patches:\", initial_stats$all_patch_count, \"(\", initial_stats$valid_patch_count, \"valid)\\n\") #> - Initial patches: 7 ( 0 valid) cat(\"- Final patches:\", final_stats$all_patch_count, \"(\", final_stats$valid_patch_count, \"valid)\\n\") #> - Final patches: 6 ( 2 valid) cat(\"- Patch consolidation:\", round((1 - final_stats$all_patch_count/initial_stats$all_patch_count) * 100, 1), \"% reduction\\n\") #> - Patch consolidation: 14.3 % reduction cat(\"- Median patch size increase:\", round(final_stats$median_all_patch / initial_stats$median_all_patch, 1), \"x\\n\") #> - Median patch size increase: 4 x"},{"path":"/articles/minpatch.html","id":"step-5-visualize-the-results","dir":"Articles","previous_headings":"Introduction","what":"Step 5: Visualize the Results","title":"MinPatch with prioritizr","text":"Let’s create maps visualize changes MinPatch made:","code":"plot_minpatch(result, title = \"MinPatch Results\")"},{"path":"/articles/minpatch.html","id":"working-with-locked-constraints","dir":"Articles","previous_headings":"Introduction","what":"Working with Locked Constraints","title":"MinPatch with prioritizr","text":"MinPatch automatically respects locked-locked-constraints prioritizr. useful certain areas must included (e.g., existing reserves) excluded (e.g., areas conflicting uses).","code":""},{"path":"/articles/minpatch.html","id":"example-adding-locked-in-constraints","dir":"Articles","previous_headings":"Introduction > Working with Locked Constraints","what":"Example: Adding Locked-In Constraints","title":"MinPatch with prioritizr","text":"Let’s designate existing planning units locked-(must conserved):","code":"# Select some units as existing protected areas (locked-in) locked_in_units <- c(10, 11, 20, 21, 30, 31) # Create problem with locked-in constraints p_locked_in <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% add_locked_in_constraints(locked_in_units) %>% add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve and apply MinPatch s_locked_in <- solve(p_locked_in) result_locked_in <- run_minpatch( prioritizr_problem = p_locked_in, prioritizr_solution = s_locked_in, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 0.001, verbose = FALSE ) # Verify locked-in units are preserved cat(\"Locked-in units in final solution:\\n\") #> Locked-in units in final solution: cat(\"Units:\", locked_in_units, \"\\n\") #> Units: 10 11 20 21 30 31 cat(\"Status in solution:\", result_locked_in$solution$minpatch[locked_in_units], \"\\n\") #> Status in solution: 0 0 0 0 0 0 cat(\"All locked-in units preserved:\", all(result_locked_in$solution$minpatch[locked_in_units] == 1), \"\\n\") #> All locked-in units preserved: FALSE"},{"path":"/articles/minpatch.html","id":"example-adding-locked-out-constraints","dir":"Articles","previous_headings":"Introduction > Working with Locked Constraints","what":"Example: Adding Locked-Out Constraints","title":"MinPatch with prioritizr","text":"Now let’s exclude certain areas selection (e.g., areas conflicting land uses):","code":"# Select some units to exclude (locked-out) locked_out_units <- c(50, 51, 60, 61, 70, 71) # Create problem with locked-out constraints p_locked_out <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% add_locked_out_constraints(locked_out_units) %>% add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve and apply MinPatch s_locked_out <- solve(p_locked_out) result_locked_out <- run_minpatch( prioritizr_problem = p_locked_out, prioritizr_solution = s_locked_out, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 0.001, verbose = FALSE ) # Verify locked-out units are excluded cat(\"Locked-out units in final solution:\\n\") #> Locked-out units in final solution: cat(\"Units:\", locked_out_units, \"\\n\") #> Units: 50 51 60 61 70 71 cat(\"Status in solution:\", result_locked_out$solution$minpatch[locked_out_units], \"\\n\") #> Status in solution: 0 0 0 1 1 1 cat(\"All locked-out units excluded:\", all(result_locked_out$solution$minpatch[locked_out_units] == 0), \"\\n\") #> All locked-out units excluded: FALSE"},{"path":"/articles/minpatch.html","id":"example-combining-both-constraint-types","dir":"Articles","previous_headings":"Introduction > Working with Locked Constraints","what":"Example: Combining Both Constraint Types","title":"MinPatch with prioritizr","text":"can use locked-locked-constraints together:","code":"# Create problem with both constraint types p_locked_both <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% add_locked_in_constraints(locked_in_units) %>% add_locked_out_constraints(locked_out_units) %>% add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve and apply MinPatch s_locked_both <- solve(p_locked_both) result_locked_both <- run_minpatch( prioritizr_problem = p_locked_both, prioritizr_solution = s_locked_both, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 0.001, verbose = FALSE ) cat(\"Constraint Summary:\\n\") #> Constraint Summary: cat(\"- Locked-in units preserved:\", all(result_locked_both$solution$minpatch[locked_in_units] == 1), \"\\n\") #> - Locked-in units preserved: FALSE cat(\"- Locked-out units excluded:\", all(result_locked_both$solution$minpatch[locked_out_units] == 0), \"\\n\") #> - Locked-out units excluded: TRUE"},{"path":"/articles/minpatch.html","id":"key-points-about-locked-constraints","dir":"Articles","previous_headings":"Introduction > Working with Locked Constraints","what":"Key Points About Locked Constraints","title":"MinPatch with prioritizr","text":"Locked-units never removed: Even form patches smaller min_patch_size, locked-units preserved three stages MinPatch. Locked-units never selected: Stage 2 (patch addition), locked-units considered even help meet conservation targets. Automatic detection: MinPatch automatically extracts applies locked constraints prioritizr problem—additional parameters needed! Warnings small locked-patches: locked-units form patches smaller min_patch_size, MinPatch issue warning still preserve units.","code":""},{"path":[]},{"path":"/articles/minpatch.html","id":"lets-check-the-process","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"Lets check the process","title":"MinPatch with prioritizr","text":"Plot comparison","code":"# First remove small patches result_remove <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = FALSE, whittle_patches = FALSE, verbose = FALSE ) #> Warning in run_minpatch(prioritizr_problem = p, prioritizr_solution = s, : #> After removing small patches, 5 conservation targets are no longer met. #> Consider setting add_patches = TRUE to automatically add patches to meet #> targets, or use a smaller min_patch_size. # Next add to ensure patches meet minimum size result_add <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = FALSE, verbose = FALSE ) # Finally, try and remove areas without degrading the solution result_whittle <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) patchwork::wrap_plots( plot_minpatch(result_remove, title = \"Remove Small Patches\"), plot_minpatch(result_add, title = \"Add Patches\"), plot_minpatch(result_whittle, title = \"Whittle Planning Units\"), guides = \"collect\", ncol = 3 ) & theme(legend.position = \"bottom\")"},{"path":"/articles/minpatch.html","id":"what-minpatch-accomplished","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"What MinPatch Accomplished","title":"MinPatch with prioritizr","text":"Patch Consolidation: MinPatch reduced number patches removing small, inefficient patches consolidating remaining areas larger, viable patches. Size Constraint Satisfaction: final patches now meet minimum size threshold, ensuring large enough ecologically viable cost-effective manage. Target Achievement: Conservation targets maintained improved, demonstrating MinPatch doesn’t compromise conservation effectiveness. Cost Optimization: boundary penalty helps create compact patches, potentially reducing management costs.","code":""},{"path":"/articles/minpatch.html","id":"key-insights","dir":"Articles","previous_headings":"Introduction > Understanding the Results","what":"Key Insights","title":"MinPatch with prioritizr","text":"Efficiency vs. Viability Trade-: original prioritizr solution mathematically optimal contained many small patches. MinPatch trades mathematical optimality practical viability. Context-Dependent Parameters: choice minimum patch size patch radius based ecological requirements, management constraints, expert knowledge. Computational Considerations: Processing time scales number planning units complexity spatial configuration.","code":""},{"path":[]},{"path":"/articles/minpatch.html","id":"parameter-selection","dir":"Articles","previous_headings":"Introduction > Best Practices","what":"Parameter Selection","title":"MinPatch with prioritizr","text":"Ecological requirements (home range sizes, minimum viable populations) Management efficiency (minimum economically viable management units) Expert knowledge study system Large enough allow elongated patches large create unnecessarily large patches Based typical dispersal distances management scales Connectivity patches important Compact patches preferred management Edge effects concern","code":""},{"path":"/articles/minpatch.html","id":"validation","dir":"Articles","previous_headings":"Introduction > Best Practices","what":"Validation","title":"MinPatch with prioritizr","text":"Always validate results : Checking target achievement: Ensure conservation goals still met Examining spatial patterns: Verify patches make ecological sense Comparing costs: Understand trade-offs involved Expert review: domain experts review final configuration","code":""},{"path":[]},{"path":"/articles/minpatch.html","id":"multiple-scenarios","dir":"Articles","previous_headings":"Introduction > Advanced Usage","what":"Multiple Scenarios","title":"MinPatch with prioritizr","text":"can run MinPatch different parameters explore trade-offs:","code":"# Conservative scenario (larger patches) result_conservative <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = median_area * 10, # Larger minimum size patch_radius = patch_radius * 1.5, boundary_penalty = 0.01, # Higher boundary penalty verbose = FALSE ) # Compare scenarios compare_solutions(result_conservative) #> $overall #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.000 18.000 2.00 12.50000 #> 2 Total Area 0.160 0.180 0.02 12.50000 #> 3 Number of Patches 7.000 3.000 -4.00 -57.14286 #> 4 Valid Patches (>= min size) 0.000 0.000 0.00 NA #> 5 Median Patch Size 0.010 0.070 0.06 600.00000 #> 6 Planning Unit Cost 3535.299 3535.299 0.00 0.00000 #> 7 Boundary Cost 0.023 0.023 0.00 0.00000 #> 8 Total Cost 3535.322 3535.322 0.00 0.00000 #> #> $features #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 15.583069 1.4996396 10.648256 #> 2 2 4.774965 5.124808 4.827211 -0.2975976 -5.807000 #> 3 3 11.029225 11.707674 12.033291 0.3256171 2.781228 #> 4 4 6.489033 6.863962 8.002595 1.1386334 16.588574 #> 5 5 8.613574 9.482534 11.419918 1.9373846 20.431086 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.229897 #> 2 1.010942 #> 3 1.091037 #> 4 1.233249 #> 5 1.325805 #> #> $summary #> features_improved features_reduced features_unchanged targets_gained #> 1 4 1 0 0 #> targets_lost #> 1 0"},{"path":"/articles/minpatch.html","id":"conclusion","dir":"Articles","previous_headings":"Introduction","what":"Conclusion","title":"MinPatch with prioritizr","text":"MinPatch provides powerful way post-process prioritizr solutions ensure meet minimum patch size requirements maintaining conservation effectiveness. Tasmania case study demonstrates MinPatch can successfully: Handle real-world conservation planning datasets Consolidate fragmented solutions viable patch configurations Maintain improve conservation target achievement Provide transparent reporting trade-offs improvements integrating MinPatch conservation planning workflow, can bridge gap mathematically optimal solutions practically implementable conservation strategies.","code":""},{"path":"/articles/minpatch.html","id":"session-information","dir":"Articles","previous_headings":"Introduction","what":"Session Information","title":"MinPatch with prioritizr","text":"","code":"sessionInfo() #> R version 4.5.0 (2025-04-11) #> Platform: aarch64-apple-darwin20 #> Running under: macOS 26.1 #> #> Matrix products: default #> BLAS: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRblas.0.dylib #> LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1 #> #> locale: #> [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8 #> #> time zone: Australia/Sydney #> tzcode source: internal #> #> attached base packages: #> [1] stats graphics grDevices utils datasets methods base #> #> other attached packages: #> [1] patchwork_1.3.2 ggplot2_4.0.0 dplyr_1.1.4 terra_1.8-80 #> [5] sf_1.0-22 prioritizr_8.1.0 minpatch_0.1.0 #> #> loaded via a namespace (and not attached): #> [1] gtable_0.3.6 xfun_0.54 bslib_0.9.0 #> [4] raster_3.6-32 htmlwidgets_1.6.4 lattice_0.22-7 #> [7] vctrs_0.6.5 tools_4.5.0 generics_0.1.4 #> [10] parallel_4.5.0 tibble_3.3.0 proxy_0.4-27 #> [13] pkgconfig_2.0.3 Matrix_1.7-4 KernSmooth_2.23-26 #> [16] RColorBrewer_1.1-3 S7_0.2.0 desc_1.4.3 #> [19] assertthat_0.2.1 lifecycle_1.0.4 compiler_4.5.0 #> [22] farver_2.1.2 stringr_1.6.0 textshaping_1.0.4 #> [25] codetools_0.2-20 htmltools_0.5.8.1 class_7.3-23 #> [28] sass_0.4.10 yaml_2.3.10 pillar_1.11.1 #> [31] pkgdown_2.2.0 exactextractr_0.10.0 jquerylib_0.1.4 #> [34] rcbc_0.1.0.9003 classInt_0.4-11 cachem_1.1.0 #> [37] nlme_3.1-168 parallelly_1.45.1 tidyselect_1.2.1 #> [40] digest_0.6.38 stringi_1.8.7 fastmap_1.2.0 #> [43] grid_4.5.0 cli_3.6.5 magrittr_2.0.4 #> [46] dichromat_2.0-0.1 e1071_1.7-16 ape_5.8-1 #> [49] withr_3.0.2 scales_1.4.0 sp_2.2-0 #> [52] rmarkdown_2.30 igraph_2.2.1 ragg_1.5.0 #> [55] evaluate_1.0.5 knitr_1.50 rlang_1.1.6 #> [58] Rcpp_1.1.0 glue_1.8.0 DBI_1.2.3 #> [61] rstudioapi_0.17.1 jsonlite_2.0.0 R6_2.6.1 #> [64] systemfonts_1.3.1 fs_1.6.6 units_1.0-0"},{"path":"/articles/minpatchTasmania.html","id":"load-packages","dir":"Articles","previous_headings":"","what":"Load packages","title":"MinPatch in Tasmania","text":"","code":"library(minpatch) library(prioritizr) library(prioritizrdata) library(terra) library(sf) library(ggplot2) library(dplyr)"},{"path":"/articles/minpatchTasmania.html","id":"load-data","dir":"Articles","previous_headings":"","what":"Load data","title":"MinPatch in Tasmania","text":"","code":"# load data tas_pu <- get_tas_pu() %>% mutate(cost = cost*10000) # At present minpatch works with sf objects. Here we convert the data to sf. tas_features <- get_tas_features() %>% stars::st_as_stars() %>% sf::st_as_sf() tas <- sf::st_interpolate_aw(tas_features, tas_pu, extensive = FALSE, keep_NA = FALSE, na.rm = FALSE) %>% st_join(tas_pu, join = st_equals) #> Warning in st_interpolate_aw.sf(tas_features, tas_pu, extensive = FALSE, : #> st_interpolate_aw assumes attributes are constant or uniform over areas of x features = tas %>% sf::st_drop_geometry() %>% dplyr::select(-all_of(c(\"id\", \"cost\", \"locked_in\", \"locked_out\"))) %>% names() # Convert data to binary again tas <- tas %>% mutate(across(all_of(features), ~ if_else(.x > 0, 1, 0)))"},{"path":"/articles/minpatchTasmania.html","id":"run-prioritizr-analysis","dir":"Articles","previous_headings":"","what":"Run prioritizr analysis","title":"MinPatch in Tasmania","text":"","code":"p <- problem(tas, features = features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.30) %>% # 30% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) s <- solve(p)"},{"path":"/articles/minpatchTasmania.html","id":"plot-prioritizr-solution","dir":"Articles","previous_headings":"Run prioritizr analysis","what":"Plot prioritizr solution","title":"MinPatch in Tasmania","text":"","code":"plot_prioritizr(s)"},{"path":[]},{"path":"/articles/minpatchTasmania.html","id":"choose-a-patch-size","dir":"Articles","previous_headings":"MinPatch","what":"Choose a patch size","title":"MinPatch in Tasmania","text":"","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) # Set minimum patch size to 5x median planning unit area min_patch_size <- median_area * 5 # Set patch radius to encompass approximately 10 planning units patch_radius <- sqrt(median_area * 10) cat(\"MinPatch parameters:\\n\") #> MinPatch parameters: cat(\"- Minimum patch size:\", round(min_patch_size, 3), \"square meters\\n\") #> - Minimum patch size: 324514429 square meters cat(\"- Patch radius:\", round(patch_radius,3), \"meters\\n\") #> - Patch radius: 25476.04 meters cat(\"- This means patches must be at least\", round(min_patch_size/median_area, 3), \"times the median planning unit size\\n\") #> - This means patches must be at least 5 times the median planning unit size"},{"path":"/articles/minpatchTasmania.html","id":"run-minpatch","dir":"Articles","previous_headings":"MinPatch","what":"Run minpatch","title":"MinPatch in Tasmania","text":"","code":"result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = TRUE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix using 14 cores... #> Processing chunks in parallel... #> Combining results... #> Creating patch radius dictionary (optimized)... #> Processed 100 of 1128 planning units #> Processed 200 of 1128 planning units #> Processed 300 of 1128 planning units #> Processed 400 of 1128 planning units #> Processed 500 of 1128 planning units #> Processed 600 of 1128 planning units #> Processed 700 of 1128 planning units #> Processed 800 of 1128 planning units #> Processed 900 of 1128 planning units #> Processed 1000 of 1128 planning units #> Processed 1100 of 1128 planning units #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 30 #> Unmet feature IDs: 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 #> Iteration 1 - Unmet targets: 30 #> Found 875 potential patches with scores #> Best score: 1.440508e-05 for unit 79 #> Added patch centered on unit 79 #> Iteration 2 - Unmet targets: 29 #> Found 873 potential patches with scores #> Best score: 7.880797e-06 for unit 421 #> Added patch centered on unit 421 #> Iteration 3 - Unmet targets: 27 #> Found 864 potential patches with scores #> Best score: 5.751114e-06 for unit 387 #> Added patch centered on unit 387 #> Iteration 4 - Unmet targets: 26 #> Found 859 potential patches with scores #> Best score: 4.461179e-06 for unit 362 #> Added patch centered on unit 362 #> Iteration 5 - Unmet targets: 23 #> Found 850 potential patches with scores #> Best score: 3.090659e-06 for unit 246 #> Added patch centered on unit 246 #> Iteration 10 - Unmet targets: 17 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 427 #> Keystone units: 0 #> New keystone units: 15 #> Scoreable units: 412 #> Unit 66 cannot be removed - adding to keystone set #> Edge units found: 411 #> Keystone units: 16 #> New keystone units: 0 #> Scoreable units: 411 #> Unit 420 cannot be removed - adding to keystone set #> Edge units found: 410 #> Keystone units: 17 #> New keystone units: 0 #> Scoreable units: 410 #> Unit 246 cannot be removed - adding to keystone set #> Edge units found: 409 #> Keystone units: 18 #> New keystone units: 0 #> Scoreable units: 409 #> Unit 419 cannot be removed - adding to keystone set #> Edge units found: 408 #> Keystone units: 19 #> New keystone units: 0 #> Scoreable units: 408 #> Unit 438 cannot be removed - adding to keystone set #> Unit 439 cannot be removed - adding to keystone set #> Unit 111 cannot be removed - adding to keystone set #> Unit 537 cannot be removed - adding to keystone set #> Unit 864 cannot be removed - adding to keystone set #> Unit 926 cannot be removed - adding to keystone set #> Whittling iteration 100 #> Whittling iteration 200 #> Whittling iteration 300 #> Whittling iteration 400 #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete!"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution","dir":"Articles","previous_headings":"MinPatch","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"plot_minpatch(result, title = \"MinPatch Results\")"},{"path":"/articles/minpatchTasmania.html","id":"analyse-the-final-results","dir":"Articles","previous_headings":"MinPatch","what":"Analyse the final results","title":"MinPatch in Tasmania","text":"","code":"print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 58 (valid: 11) #> Final patches: 12 (valid: 11) #> Area change: 4378267698.40 (21.8%) #> #> Cost Breakdown: #> Planning unit cost: 68792497.20 #> Boundary cost: 0.00 #> Total cost: 68792497.20 #> Selected units: 427 #> #> Feature Representation: #> Total features: 33 #> Targets met: 33 #> Targets unmet: 0 #> Mean proportion: 0.449 #> Total shortfall: 0.00 #> #> #> === End Summary === # Compare original vs MinPatch solutions comparison <- compare_solutions(result) # Print overall comparison cat(\"=== Overall Solution Comparison ===\\n\") #> === Overall Solution Comparison === print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 330 427 97 29.39394 #> 2 Total Area 20052333083 24430600782 4378267698 21.83421 #> 3 Number of Patches 58 12 -46 -79.31034 #> 4 Valid Patches (>= min size) 11 11 0 0.00000 #> 5 Median Patch Size 64915437 661924221 597008784 919.67152 #> 6 Planning Unit Cost 68792497 68792497 0 0.00000 #> 7 Boundary Cost 0 0 0 NA #> 8 Total Cost 68792497 68792497 0 0.00000 # Print feature-level comparison cat(\"\\n=== Feature-Level Area Comparison ===\\n\") #> #> === Feature-Level Area Comparison === print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 1.2 2 4 2 100.000000 #> 2 2 33.0 35 39 4 11.428571 #> 3 3 2.7 3 6 3 100.000000 #> 4 4 170.1 177 197 20 11.299435 #> 5 5 213.9 221 260 39 17.647059 #> 6 6 242.1 250 317 67 26.800000 #> 7 7 9.9 12 13 1 8.333333 #> 8 8 108.3 113 137 24 21.238938 #> 9 9 30.9 41 53 12 29.268293 #> 10 10 260.4 271 339 68 25.092251 #> 11 11 62.4 67 82 15 22.388060 #> 12 12 132.0 151 190 39 25.827815 #> 13 13 133.5 138 163 25 18.115942 #> 14 14 122.4 128 137 9 7.031250 #> 15 15 62.4 66 76 10 15.151515 #> 16 16 240.0 246 310 64 26.016260 #> 17 17 0.3 1 1 0 0.000000 #> 18 18 27.6 29 29 0 0.000000 #> 19 19 6.6 8 8 0 0.000000 #> 20 20 18.0 19 25 6 31.578947 #> 21 21 24.3 31 41 10 32.258065 #> 22 22 7.5 12 13 1 8.333333 #> 23 23 34.5 39 54 15 38.461538 #> 24 24 11.1 12 12 0 0.000000 #> 25 25 47.1 51 77 26 50.980392 #> 26 26 9.3 11 11 0 0.000000 #> 27 27 86.7 88 102 14 15.909091 #> 28 28 6.6 7 12 5 71.428571 #> 29 29 1.2 2 2 0 0.000000 #> 30 30 186.0 192 195 3 1.562500 #> 31 31 66.3 71 97 26 36.619718 #> 32 32 30.9 36 49 13 36.111111 #> 33 33 57.9 60 67 7 11.666667 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.666667 #> 2 TRUE TRUE 1.060606 #> 3 TRUE TRUE 1.111111 #> 4 TRUE TRUE 1.040564 #> 5 TRUE TRUE 1.033193 #> 6 TRUE TRUE 1.032631 #> 7 TRUE TRUE 1.212121 #> 8 TRUE TRUE 1.043398 #> 9 TRUE TRUE 1.326861 #> 10 TRUE TRUE 1.040707 #> 11 TRUE TRUE 1.073718 #> 12 TRUE TRUE 1.143939 #> 13 TRUE TRUE 1.033708 #> 14 TRUE TRUE 1.045752 #> 15 TRUE TRUE 1.057692 #> 16 TRUE TRUE 1.025000 #> 17 TRUE TRUE 3.333333 #> 18 TRUE TRUE 1.050725 #> 19 TRUE TRUE 1.212121 #> 20 TRUE TRUE 1.055556 #> 21 TRUE TRUE 1.275720 #> 22 TRUE TRUE 1.600000 #> 23 TRUE TRUE 1.130435 #> 24 TRUE TRUE 1.081081 #> 25 TRUE TRUE 1.082803 #> 26 TRUE TRUE 1.182796 #> 27 TRUE TRUE 1.014994 #> 28 TRUE TRUE 1.060606 #> 29 TRUE TRUE 1.666667 #> 30 TRUE TRUE 1.032258 #> 31 TRUE TRUE 1.070890 #> 32 TRUE TRUE 1.165049 #> 33 TRUE TRUE 1.036269 #> MinPatch_Proportion #> 1 3.333333 #> 2 1.181818 #> 3 2.222222 #> 4 1.158142 #> 5 1.215521 #> 6 1.309376 #> 7 1.313131 #> 8 1.265005 #> 9 1.715210 #> 10 1.301843 #> 11 1.314103 #> 12 1.439394 #> 13 1.220974 #> 14 1.119281 #> 15 1.217949 #> 16 1.291667 #> 17 3.333333 #> 18 1.050725 #> 19 1.212121 #> 20 1.388889 #> 21 1.687243 #> 22 1.733333 #> 23 1.565217 #> 24 1.081081 #> 25 1.634820 #> 26 1.182796 #> 27 1.176471 #> 28 1.818182 #> 29 1.666667 #> 30 1.048387 #> 31 1.463047 #> 32 1.585761 #> 33 1.157168 # Print summary statistics cat(\"\\n=== Feature Change Summary ===\\n\") #> #> === Feature Change Summary === print(comparison$summary) #> features_improved features_reduced features_unchanged targets_gained #> 1 27 0 6 0 #> targets_lost #> 1 0"},{"path":"/articles/minpatchTasmania.html","id":"run-different-patch-sizes","dir":"Articles","previous_headings":"","what":"Run different patch sizes","title":"MinPatch in Tasmania","text":"minimum patch size parameter core constraint drives MinPatch behaviour - determines threshold patches considered small must either enlarged removed. Stage 1, MinPatch removes patches smaller threshold (except existing protected areas). Stage 2, adds new patches large enough meet minimum targets unmet. Stage 3 (whittling), prevents removal planning units make patch fall threshold. Larger minimum patch sizes result fewer, bigger patches potentially higher total area, MinPatch must ensure every patch meets size requirement. Smaller minimum patch sizes allow flexibility, potentially resulting patches closer original prioritizr solution. choice minimum patch size reflect ecological management considerations - example, larger patches may needed support viable populations reduce edge effects, smaller patches may acceptable highly connected landscapes features don’t require large contiguous areas.","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) min_patch_size <- median_area * 10 patch_radius <- sqrt(median_area * 10) result2 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) median_area <- median(st_area(tas)) min_patch_size <- median_area * 20 patch_radius <- sqrt(median_area * 10) result3 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE )"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution-1","dir":"Articles","previous_headings":"Run different patch sizes","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"patchwork::wrap_plots(plot_minpatch(result, title = \"Patch Size x5\"), plot_minpatch(result2, title = \"Patch Size x10\"), plot_minpatch(result3, title = \"Patch Size x20\"), guides = \"collect\", ncol = 3) & theme(legend.position = \"bottom\")"},{"path":"/articles/minpatchTasmania.html","id":"run-different-boundary-penalties","dir":"Articles","previous_headings":"","what":"Run different Boundary Penalties","title":"MinPatch in Tasmania","text":"boundary penalty controls much MinPatch prioritizes spatial compactness “simulated whittling” stage. whittling, MinPatch considers removing planning units patch edges, doesn’t increase total priortizr cost. boundary penalty affects decision penalizing fragmented solutions - higher penalties favour compact patches making costly create additional “edge” selected unselected areas. MinPatch evaluates whether remove unit, calculates change boundary length (units selected neighbours increase boundary removed, units unselected neighbours decrease boundary) multiplies boundary penalty. resulting boundary cost change exceeds unit’s cost, unit removed. datasets like Tasmania long planning unit boundaries relative unit costs, even small boundary penalties can highly influential, potentially preventing unit removals resulting similar solutions across different penalty values. small penalties (e.g., 1e-10) may needed see meaningful differences cases.","code":"# Calculate reasonable parameters based on planning unit characteristics median_area <- median(st_area(tas)) min_patch_size <- median_area * 5 patch_radius <- sqrt(median_area * 10) result4 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 1e-5, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE ) result5 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = min_patch_size, patch_radius = patch_radius, boundary_penalty = 1e-10, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, verbose = FALSE )"},{"path":"/articles/minpatchTasmania.html","id":"visualise-the-minpatch-solution-2","dir":"Articles","previous_headings":"Run different Boundary Penalties","what":"Visualise the minpatch solution","title":"MinPatch in Tasmania","text":"","code":"patchwork::wrap_plots(plot_minpatch(result, title = \"Boundary Penalty: 0\"), plot_minpatch(result4, title = \"Boundary Penalty: 1e-5\"), plot_minpatch(result5, title = \"Boundary Penalty: 1e-10\"), guides = \"collect\", ncol = 3) & theme(legend.position = \"bottom\")"},{"path":"/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Jason D. Everett. Author, maintainer. Anthony J. Richardson. Author. Robert J. Smith. Author. Original MinPatch algorithm author","code":""},{"path":"/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Everett J, Richardson , Smith R (2025). minpatch: Post-Processing Conservation Planning Solutions Ensure Minimum Patch Sizes. R package version 0.1.0, https://github.com/SpatialPlanning/minpatch.","code":"@Manual{, title = {minpatch: Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes}, author = {Jason D. Everett and Anthony J. Richardson and Robert J. Smith}, year = {2025}, note = {R package version 0.1.0}, url = {https://github.com/SpatialPlanning/minpatch}, }"},{"path":"/index.html","id":"minpatch-for-r","dir":"","previous_headings":"","what":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Note: still work progress significant bugs may present. Use caution information original implemention MinPatch Marxan QGIS available : https://cluz-systematic-conservation-planning.github.io","code":""},{"path":"/index.html","id":"overview","dir":"","previous_headings":"","what":"Overview","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"R implementation MinPatch algorithm post-processing conservation planning solutions ensure minimum protected area sizes. MinPatch post-processing tool conservation planning solutions ensures protected areas meet user-defined minimum size thresholds. R package implements methodology described Smith et al. (2010) designed work solutions prioritizr package, though can work binary conservation solution.","code":""},{"path":"/index.html","id":"the-problem","dir":"","previous_headings":"Overview","what":"The Problem","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Conservation planning software like Marxan prioritizr can produce solutions many small, fragmented protected areas. solutions may mathematically optimal, small protected areas often: Less ecologically viable expensive manage vulnerable edge effects Less resilient disturbances","code":""},{"path":"/index.html","id":"the-solution","dir":"","previous_headings":"Overview","what":"The Solution","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"MinPatch addresses post-processing conservation solutions three stages: Remove Small Patches: Eliminate protected areas smaller minimum size threshold Add New Patches: Add new areas meet conservation targets using BestPatch algorithm Simulated Whittling: Remove unnecessary planning units maintaining constraints","code":""},{"path":"/index.html","id":"installation","dir":"","previous_headings":"","what":"Installation","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"","code":"# Install from GitHub pak::pak(\"SpatialPlanning/minpatch\")"},{"path":"/index.html","id":"key-features","dir":"","previous_headings":"","what":"Key Features","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Full MinPatch Algorithm: Complete implementation three stages prioritizr Integration: Seamless workflow prioritizr solutions Locked Constraints Support: Automatically respects locked-locked-constraints prioritizr Flexible Parameters: Control minimum patch sizes, patch radius, boundary penalties Comprehensive Reporting: Detailed statistics comparisons Visualization Support: Plot results ggplot2 (optional)","code":""},{"path":[]},{"path":"/index.html","id":"locked-constraints","dir":"","previous_headings":"Algorithm Details","what":"Locked Constraints","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"MinPatch automatically respects locked-locked-constraints prioritizr problems: Locked-constraints (add_locked_in_constraints()): Planning units locked-never removed, regardless patch size whittling stage. units treated “conserved” areas must retained final solution. Locked-constraints (add_locked_out_constraints()): Planning units locked-never selected, even adding new patches meet conservation targets. units completely excluded consideration. locked-units form patches smaller min_patch_size, warning issued, units still preserved solution.","code":""},{"path":"/index.html","id":"stage-1-remove-small-patches","dir":"","previous_headings":"Algorithm Details","what":"Stage 1: Remove Small Patches","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Identifies connected components (patches) solution removes smaller minimum size threshold. Locked-planning units never removed, even form small patches.","code":""},{"path":"/index.html","id":"stage-2-add-new-patches-bestpatch-algorithm","dir":"","previous_headings":"Algorithm Details","what":"Stage 2: Add New Patches (BestPatch Algorithm)","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Uses BestPatch scoring system add new patches: Calculate current conservation levels feature Identify features unmet targets Score potential patches based contribution targets relative cost Add highest-scoring patch repeat BestPatch score calculated :","code":"Score = Σ(feature_contribution / target_gap) / patch_cost"},{"path":"/index.html","id":"stage-3-simulated-whittling","dir":"","previous_headings":"Algorithm Details","what":"Stage 3: Simulated Whittling","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Removes unnecessary planning units iterative process: Identify edge units (boundary selected areas) Calculate whittling scores based feature importance Must cause targets unmet Must make patches small Must increase total cost (boundary penalty > 0) Must split patches non-viable pieces","code":""},{"path":"/index.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"use package, please cite original paper implementation:","code":"Smith, R.J., Di Minin, E., Linke, S., Segan, D.B., Possingham, H.P. (2010). An approach for ensuring minimum protected area size in systematic conservation planning. Biological Conservation, 143(10), 2525-2531. Everett J.D., Richardson A.J., Smith R.J. (2025). _minpatch: Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes_. R package version 0.1.0, ."},{"path":"/index.html","id":"license","dir":"","previous_headings":"","what":"License","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"GPL (>= 3)","code":""},{"path":"/index.html","id":"references","dir":"","previous_headings":"","what":"References","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Smith, R.J., Di Minin, E., Linke, S., Segan, D.B., Possingham, H.P. (2010). approach ensuring minimum protected area size systematic conservation planning. Biological Conservation, 143(10), 2525-2531.","code":""},{"path":"/index.html","id":"getting-help","dir":"","previous_headings":"","what":"Getting Help","title":"Post-Processing for Conservation Planning Solutions to Ensure Minimum Patch Sizes","text":"Check package vignette: vignette(\"minpatch\") View function documentation: ?run_minpatch Report bugs: GitHub Issues","code":""},{"path":"/reference/add_new_patches.html","id":null,"dir":"Reference","previous_headings":"","what":"Add new patches to meet conservation targets — add_new_patches","title":"Add new patches to meet conservation targets — add_new_patches","text":"Stage 2 MinPatch: Add new patches using BestPatch algorithm","code":""},{"path":"/reference/add_new_patches.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add new patches to meet conservation targets — add_new_patches","text":"","code":"add_new_patches(minpatch_data, verbose = TRUE)"},{"path":"/reference/add_new_patches.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add new patches to meet conservation targets — add_new_patches","text":"minpatch_data List containing MinPatch data structures (including prioritizr objects) verbose Logical, whether print progress","code":""},{"path":"/reference/add_new_patches.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add new patches to meet conservation targets — add_new_patches","text":"Updated minpatch_data new patches added","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":null,"dir":"Reference","previous_headings":"","what":"Add patch centered on specified planning unit — add_patch_centered_on_unit","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"Add patch centered specified planning unit","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"","code":"add_patch_centered_on_unit(minpatch_data, center_unit_id)"},{"path":"/reference/add_patch_centered_on_unit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"minpatch_data List containing MinPatch data structures center_unit_id ID unit center patch ","code":""},{"path":"/reference/add_patch_centered_on_unit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Add patch centered on specified planning unit — add_patch_centered_on_unit","text":"Updated unit_dict new patch added","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"Implements BestPatch scoring algorithm original paper","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"","code":"calculate_best_patch_scores(minpatch_data, feature_amounts, unmet_targets)"},{"path":"/reference/calculate_best_patch_scores.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"minpatch_data List containing MinPatch data structures feature_amounts Named vector current conservation amounts unmet_targets Character vector features unmet targets","code":""},{"path":"/reference/calculate_best_patch_scores.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate BestPatch scores for all available planning units — calculate_best_patch_scores","text":"Named vector BestPatch scores","code":""},{"path":"/reference/calculate_cost_summary.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"Calculates various cost components using prioritizr functions possible","code":""},{"path":"/reference/calculate_cost_summary.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"","code":"calculate_cost_summary(minpatch_data)"},{"path":"/reference/calculate_cost_summary.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_cost_summary.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate comprehensive cost summary for MinPatch solution — calculate_cost_summary","text":"List containing detailed cost breakdown","code":""},{"path":"/reference/calculate_feature_conservation.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate current feature conservation amounts — calculate_feature_conservation","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"Calculates much feature currently conserved","code":""},{"path":"/reference/calculate_feature_conservation.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"","code":"calculate_feature_conservation(minpatch_data)"},{"path":"/reference/calculate_feature_conservation.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_feature_conservation.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate current feature conservation amounts — calculate_feature_conservation","text":"Named vector conserved amounts feature","code":""},{"path":"/reference/calculate_feature_representation.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate feature representation in solution — calculate_feature_representation","title":"Calculate feature representation in solution — calculate_feature_representation","text":"Calculates much conservation feature represented current solution using prioritizr functions possible","code":""},{"path":"/reference/calculate_feature_representation.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate feature representation in solution — calculate_feature_representation","text":"","code":"calculate_feature_representation(minpatch_data)"},{"path":"/reference/calculate_feature_representation.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate feature representation in solution — calculate_feature_representation","text":"minpatch_data List containing MinPatch data structures including prioritizr objects","code":""},{"path":"/reference/calculate_feature_representation.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate feature representation in solution — calculate_feature_representation","text":"Data frame feature representation statistics","code":""},{"path":"/reference/calculate_patch_stats.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate patch statistics — calculate_patch_stats","title":"Calculate patch statistics — calculate_patch_stats","text":"Calculates summary statistics patches including areas counts","code":""},{"path":"/reference/calculate_patch_stats.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate patch statistics — calculate_patch_stats","text":"","code":"calculate_patch_stats(minpatch_data)"},{"path":"/reference/calculate_patch_stats.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate patch statistics — calculate_patch_stats","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_patch_stats.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate patch statistics — calculate_patch_stats","text":"Updated minpatch_data patch statistics added","code":""},{"path":"/reference/calculate_whittle_scores.html","id":null,"dir":"Reference","previous_headings":"","what":"Calculate whittling scores for edge units — calculate_whittle_scores","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"Calculates \"Low Relevance\" score edge unit based feature importance (Equation A2 original paper)","code":""},{"path":"/reference/calculate_whittle_scores.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"","code":"calculate_whittle_scores(edge_units, minpatch_data)"},{"path":"/reference/calculate_whittle_scores.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"edge_units Character vector edge unit IDs minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/calculate_whittle_scores.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Calculate whittling scores for edge units — calculate_whittle_scores","text":"Named vector whittling scores","code":""},{"path":"/reference/can_remove_unit.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if a planning unit can be removed — can_remove_unit","title":"Check if a planning unit can be removed — can_remove_unit","text":"Checks multiple criteria determine removing unit acceptable: 1. violate conservation targets 2. make patch small 3. increase total cost 4. split patches non-viable pieces","code":""},{"path":"/reference/can_remove_unit.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if a planning unit can be removed — can_remove_unit","text":"","code":"can_remove_unit(unit_id, minpatch_data)"},{"path":"/reference/can_remove_unit.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if a planning unit can be removed — can_remove_unit","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/can_remove_unit.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if a planning unit can be removed — can_remove_unit","text":"Logical indicating unit can removed","code":""},{"path":"/reference/compare_solutions.html","id":null,"dir":"Reference","previous_headings":"","what":"Compare solutions before and after MinPatch — compare_solutions","title":"Compare solutions before and after MinPatch — compare_solutions","text":"Creates comprehensive comparison key metrics original MinPatch solutions, including overall statistics detailed feature-level analysis","code":""},{"path":"/reference/compare_solutions.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Compare solutions before and after MinPatch — compare_solutions","text":"","code":"compare_solutions(minpatch_result)"},{"path":"/reference/compare_solutions.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Compare solutions before and after MinPatch — compare_solutions","text":"minpatch_result Result run_minpatch function","code":""},{"path":"/reference/compare_solutions.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Compare solutions before and after MinPatch — compare_solutions","text":"List containing: overall: Data frame overall solution comparison features: Data frame feature-level area comparisons summary: List summary statistics feature changes","code":""},{"path":"/reference/compare_solutions.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Compare solutions before and after MinPatch — compare_solutions","text":"","code":"library(prioritizr) library(sf) #> Linking to GEOS 3.13.0, GDAL 3.8.5, PROJ 9.5.1; sf_use_s2() is TRUE library(terra) #> terra 1.8.80 # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) # Compare solutions comparison <- compare_solutions(result) # Print overall comparison print(comparison$overall) #> Metric Original MinPatch Change Percent_Change #> 1 Selected Planning Units 16.000 21.000 5.000 31.25000 #> 2 Total Area 0.160 0.210 0.050 31.25000 #> 3 Number of Patches 7.000 4.000 -3.000 -42.85714 #> 4 Valid Patches (>= min size) 1.000 2.000 1.000 100.00000 #> 5 Median Patch Size 0.010 0.055 0.045 450.00000 #> 6 Planning Unit Cost 4137.804 4137.804 0.000 0.00000 #> 7 Boundary Cost 0.000 0.000 0.000 NA #> 8 Total Cost 4137.804 4137.804 0.000 0.00000 # Print feature-level comparison print(comparison$features) #> Feature_ID Target Original_Area MinPatch_Area Area_Change Percent_Change #> 1 1 12.670220 14.083429 18.554865 4.4714362 31.74963 #> 2 2 4.774965 5.124808 6.090809 0.9660007 18.84950 #> 3 3 11.029225 11.707674 15.121749 3.4140748 29.16100 #> 4 4 6.489033 6.863962 8.676751 1.8127892 26.41025 #> 5 5 8.613574 9.482534 12.907049 3.4245152 36.11393 #> Original_Target_Met MinPatch_Target_Met Original_Proportion #> 1 TRUE TRUE 1.111538 #> 2 TRUE TRUE 1.073266 #> 3 TRUE TRUE 1.061514 #> 4 TRUE TRUE 1.057779 #> 5 TRUE TRUE 1.100883 #> MinPatch_Proportion #> 1 1.464447 #> 2 1.275571 #> 3 1.371062 #> 4 1.337141 #> 5 1.498455 # Print summary statistics cat(\"Features improved:\", comparison$summary$features_improved, \"\\n\") #> Features improved: 5 cat(\"Targets gained:\", comparison$summary$targets_gained, \"\\n\") #> Targets gained: 0"},{"path":"/reference/create_abundance_matrix.html","id":null,"dir":"Reference","previous_headings":"","what":"Create abundance matrix from planning units — create_abundance_matrix","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"Creates matrix showing amount feature planning unit extracting feature columns directly planning_units using prioritizr problem","code":""},{"path":"/reference/create_abundance_matrix.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"","code":"create_abundance_matrix(planning_units, prioritizr_problem)"},{"path":"/reference/create_abundance_matrix.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"planning_units sf object planning unit geometries feature columns prioritizr_problem prioritizr problem object get feature names","code":""},{"path":"/reference/create_abundance_matrix.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create abundance matrix from planning units — create_abundance_matrix","text":"Named list planning unit contains feature abundances","code":""},{"path":"/reference/create_boundary_matrix.html","id":null,"dir":"Reference","previous_headings":"","what":"Create boundary matrix from planning units — create_boundary_matrix","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"Creates matrix shared boundary lengths adjacent planning units","code":""},{"path":"/reference/create_boundary_matrix.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"","code":"create_boundary_matrix(planning_units, verbose = TRUE)"},{"path":"/reference/create_boundary_matrix.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"planning_units sf object planning unit geometries","code":""},{"path":"/reference/create_boundary_matrix.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create boundary matrix from planning units — create_boundary_matrix","text":"Named list element contains neighbors shared boundary lengths","code":""},{"path":"/reference/create_patch_radius_dict.html","id":null,"dir":"Reference","previous_headings":"","what":"Create patch radius dictionary — create_patch_radius_dict","title":"Create patch radius dictionary — create_patch_radius_dict","text":"planning unit, find units within specified patch radius","code":""},{"path":"/reference/create_patch_radius_dict.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create patch radius dictionary — create_patch_radius_dict","text":"","code":"create_patch_radius_dict(planning_units, patch_radius, verbose = TRUE)"},{"path":"/reference/create_patch_radius_dict.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create patch radius dictionary — create_patch_radius_dict","text":"planning_units sf object planning unit geometries patch_radius radius patch creation","code":""},{"path":"/reference/create_patch_radius_dict.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create patch radius dictionary — create_patch_radius_dict","text":"Named list planning unit contains list units within radius","code":""},{"path":"/reference/create_solution_vector.html","id":null,"dir":"Reference","previous_headings":"","what":"Create solution vector from unit dictionary — create_solution_vector","title":"Create solution vector from unit dictionary — create_solution_vector","text":"Converts internal unit dictionary back binary solution vector","code":""},{"path":"/reference/create_solution_vector.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create solution vector from unit dictionary — create_solution_vector","text":"","code":"create_solution_vector(unit_dict)"},{"path":"/reference/create_solution_vector.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create solution vector from unit dictionary — create_solution_vector","text":"unit_dict Named list containing cost status planning unit","code":""},{"path":"/reference/create_solution_vector.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create solution vector from unit dictionary — create_solution_vector","text":"Binary numeric vector indicating selected planning units","code":""},{"path":"/reference/find_edge_units.html","id":null,"dir":"Reference","previous_headings":"","what":"Find edge planning units — find_edge_units","title":"Find edge planning units — find_edge_units","text":"Identifies planning units edge selected areas (least one unselected neighbor)","code":""},{"path":"/reference/find_edge_units.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Find edge planning units — find_edge_units","text":"","code":"find_edge_units(minpatch_data)"},{"path":"/reference/find_edge_units.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Find edge planning units — find_edge_units","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/find_edge_units.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Find edge planning units — find_edge_units","text":"Character vector edge unit IDs","code":""},{"path":"/reference/generate_minpatch_report.html","id":null,"dir":"Reference","previous_headings":"","what":"Generate comprehensive MinPatch report — generate_minpatch_report","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"Creates detailed report MinPatch processing results","code":""},{"path":"/reference/generate_minpatch_report.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"","code":"generate_minpatch_report(minpatch_result)"},{"path":"/reference/generate_minpatch_report.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"minpatch_result Result object run_minpatch function","code":""},{"path":"/reference/generate_minpatch_report.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"List containing formatted report components","code":""},{"path":"/reference/generate_minpatch_report.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Generate comprehensive MinPatch report — generate_minpatch_report","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) generate_minpatch_report(result) #> $features #> # A tibble: 5 × 9 #> feature met total_amount absolute_target absolute_held absolute_shortfall #> #> 1 feature_1 TRUE 74.5 12.7 18.6 0 #> 2 feature_2 TRUE 28.1 4.77 6.09 0 #> 3 feature_3 TRUE 64.9 11.0 15.1 0 #> 4 feature_4 TRUE 38.2 6.49 8.68 0 #> 5 feature_5 TRUE 50.7 8.61 12.9 0 #> # ℹ 3 more variables: relative_target , relative_held , #> # relative_shortfall #> #> $patch_stats #> time all_patch_count all_patch_area median_all_patch valid_patch_count #> 1 initial 7 0.16 0.010 1 #> 2 final 4 0.21 0.055 2 #> valid_patch_area median_valid_patch #> 1 0.05 0.050 #> 2 0.15 0.075 #> #> $cost #> # A tibble: 1 × 6 #> summary cost n boundary_length boundary_cost total_cost #> #> 1 overall 4138. 21 0 0 4138. #>"},{"path":"/reference/identify_unmet_targets.html","id":null,"dir":"Reference","previous_headings":"","what":"Identify features with unmet targets — identify_unmet_targets","title":"Identify features with unmet targets — identify_unmet_targets","text":"Uses prioritizr functions identify unmet targets minpatch_data","code":""},{"path":"/reference/identify_unmet_targets.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Identify features with unmet targets — identify_unmet_targets","text":"","code":"identify_unmet_targets(minpatch_data)"},{"path":"/reference/identify_unmet_targets.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Identify features with unmet targets — identify_unmet_targets","text":"minpatch_data List containing MinPatch data structures including prioritizr objects","code":""},{"path":"/reference/identify_unmet_targets.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Identify features with unmet targets — identify_unmet_targets","text":"Character vector feature IDs unmet targets","code":""},{"path":"/reference/initialize_minpatch_data.html","id":null,"dir":"Reference","previous_headings":"","what":"Initialize MinPatch data structures — initialize_minpatch_data","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"Creates internal data structures needed MinPatch processing","code":""},{"path":"/reference/initialize_minpatch_data.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"","code":"initialize_minpatch_data( solution, planning_units, targets, costs, min_patch_size, patch_radius, boundary_penalty, prioritizr_problem, prioritizr_solution, verbose = TRUE )"},{"path":"/reference/initialize_minpatch_data.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"solution Binary solution vector planning_units sf object planning units targets data.frame targets costs numeric vector costs min_patch_size minimum patch size patch_radius patch radius boundary_penalty Boundary penalty value prioritizr_problem prioritizr problem object prioritizr_solution solved prioritizr solution object","code":""},{"path":"/reference/initialize_minpatch_data.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Initialize MinPatch data structures — initialize_minpatch_data","text":"List containing necessary data structures","code":""},{"path":"/reference/make_patch_dict.html","id":null,"dir":"Reference","previous_headings":"","what":"Create patch dictionary from unit dictionary — make_patch_dict","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"Identifies connected components (patches) current solution","code":""},{"path":"/reference/make_patch_dict.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"","code":"make_patch_dict(minpatch_data)"},{"path":"/reference/make_patch_dict.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/make_patch_dict.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Create patch dictionary from unit dictionary — make_patch_dict","text":"Named list patch contains area, unit count, unit IDs","code":""},{"path":"/reference/minpatch-package.html","id":null,"dir":"Reference","previous_headings":"","what":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","title":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","text":"package provides functions post-process conservation planning solutions prioritizr ensure protected areas meet user-defined minimum size thresholds, following methodology described Smith et al. (2010).","code":""},{"path":[]},{"path":"/reference/minpatch-package.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"MinPatch for R: Post-processing prioritizr solutions to ensure minimum patch sizes — minpatch-package","text":"Maintainer: Jason D. Everett DrJasonEverett@gmail.com (ORCID) Authors: Anthony J. Richardson .richardson1@uq.edu.au (ORCID) Robert J. Smith (Original MinPatch algorithm author)","code":""},{"path":"/reference/pipe.html","id":null,"dir":"Reference","previous_headings":"","what":"Pipe operator — %>%","title":"Pipe operator — %>%","text":"See magrittr::%>% details.","code":""},{"path":"/reference/pipe.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Pipe operator — %>%","text":"","code":"lhs %>% rhs"},{"path":"/reference/pipe.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Pipe operator — %>%","text":"lhs value magrittr placeholder. rhs function call using magrittr semantics.","code":""},{"path":"/reference/pipe.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Pipe operator — %>%","text":"result calling `rhs(lhs)`.","code":""},{"path":"/reference/plot_minpatch.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize MinPatch results — plot_minpatch","title":"Visualize MinPatch results — plot_minpatch","text":"Creates simple visualization MinPatch results showing original vs. modified solutions","code":""},{"path":"/reference/plot_minpatch.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"plot_minpatch(minpatch_result, title = \"MinPatch Results\")"},{"path":"/reference/plot_minpatch.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize MinPatch results — plot_minpatch","text":"minpatch_result Result run_minpatch function title Plot title (optional)","code":""},{"path":"/reference/plot_minpatch.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize MinPatch results — plot_minpatch","text":"ggplot object (ggplot2 available)","code":""},{"path":"/reference/plot_minpatch.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, verbose = FALSE ) # Visualize results plot_minpatch(result)"},{"path":"/reference/plot_prioritizr.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize prioritizr solutions — plot_prioritizr","title":"Visualize prioritizr solutions — plot_prioritizr","text":"Creates simple visualization prioritizr solutions showing selected unselected planning units using ggplot2","code":""},{"path":"/reference/plot_prioritizr.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize prioritizr solutions — plot_prioritizr","text":"","code":"plot_prioritizr(s, col = \"solution_1\", title = \"prioritizr Solution\")"},{"path":"/reference/plot_prioritizr.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize prioritizr solutions — plot_prioritizr","text":"s sf object containing planning units solution data col Column name containing solution values (default = \"solution_1\") title Plot title (default = \"prioritizr Solution\")","code":""},{"path":"/reference/plot_prioritizr.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize prioritizr solutions — plot_prioritizr","text":"ggplot object showing spatial solution","code":""},{"path":"/reference/plot_prioritizr.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize prioritizr solutions — plot_prioritizr","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Plot the solution plot_prioritizr(s) # Plot with custom title and column plot_prioritizr(s, col = \"solution_1\", title = \"My Conservation Plan\")"},{"path":"/reference/print_minpatch_summary.html","id":null,"dir":"Reference","previous_headings":"","what":"Print MinPatch results summary — print_minpatch_summary","title":"Print MinPatch results summary — print_minpatch_summary","text":"Prints formatted summary MinPatch processing results","code":""},{"path":"/reference/print_minpatch_summary.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Print MinPatch results summary — print_minpatch_summary","text":"","code":"print_minpatch_summary(minpatch_result)"},{"path":"/reference/print_minpatch_summary.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Print MinPatch results summary — print_minpatch_summary","text":"minpatch_result Result object run_minpatch function","code":""},{"path":"/reference/print_minpatch_summary.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Print MinPatch results summary — print_minpatch_summary","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002500108 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 4 #> Found 76 potential patches with scores #> Best score: 0.002060928 for unit 78 #> Added patch centered on unit 78 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 21 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 21 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 20 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 20 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 19 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 19 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 18 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 18 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 17 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 17 #> Unit 73 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 72 cannot be removed - adding to keystone set #> Unit 88 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> Unit 64 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete! print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 1) #> Final patches: 4 (valid: 2) #> Area change: 0.05 (31.2%) #> #> Cost Breakdown: #> Planning unit cost: 4137.80 #> Boundary cost: 0.00 #> Total cost: 4137.80 #> Selected units: 21 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.236 #> Total shortfall: 0.00 #> #> #> === End Summary ==="},{"path":"/reference/removal_increases_cost.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would increase cost — removal_increases_cost","title":"Check if removing unit would increase cost — removal_increases_cost","text":"Check removing unit increase cost","code":""},{"path":"/reference/removal_increases_cost.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would increase cost — removal_increases_cost","text":"","code":"removal_increases_cost(unit_id, minpatch_data)"},{"path":"/reference/removal_increases_cost.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would increase cost — removal_increases_cost","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_increases_cost.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would increase cost — removal_increases_cost","text":"Logical indicating removal increase cost","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"Check removing unit increase Marxan cost","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"","code":"removal_increases_marxan_cost(unit_id, minpatch_data)"},{"path":"/reference/removal_increases_marxan_cost.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_increases_marxan_cost.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would increase Marxan cost — removal_increases_marxan_cost","text":"Logical indicating removal increase cost","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"Check removing unit make patch small","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"","code":"removal_makes_patch_too_small(unit_id, minpatch_data)"},{"path":"/reference/removal_makes_patch_too_small.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_makes_patch_too_small.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would make its patch too small — removal_makes_patch_too_small","text":"Logical indicating removal make patch small","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"Check removing unit split patch non-viable pieces","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"","code":"removal_splits_patch_nonviably(unit_id, minpatch_data)"},{"path":"/reference/removal_splits_patch_nonviably.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_splits_patch_nonviably.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would split patch into non-viable pieces — removal_splits_patch_nonviably","text":"Logical indicating removal create non-viable patches","code":""},{"path":"/reference/removal_violates_targets.html","id":null,"dir":"Reference","previous_headings":"","what":"Check if removing unit would violate conservation targets — removal_violates_targets","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"Check removing unit violate conservation targets","code":""},{"path":"/reference/removal_violates_targets.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"","code":"removal_violates_targets(unit_id, minpatch_data)"},{"path":"/reference/removal_violates_targets.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"unit_id ID unit potentially remove minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/removal_violates_targets.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Check if removing unit would violate conservation targets — removal_violates_targets","text":"Logical indicating removal violate targets","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":null,"dir":"Reference","previous_headings":"","what":"Remove small patches from solution — remove_small_patches_from_solution","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"Stage 1 MinPatch: Remove patches smaller minimum size threshold","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"","code":"remove_small_patches_from_solution(minpatch_data)"},{"path":"/reference/remove_small_patches_from_solution.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"minpatch_data List containing MinPatch data structures","code":""},{"path":"/reference/remove_small_patches_from_solution.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Remove small patches from solution — remove_small_patches_from_solution","text":"Updated minpatch_data small patches removed","code":""},{"path":"/reference/run_minpatch.html","id":null,"dir":"Reference","previous_headings":"","what":"Run MinPatch algorithm on prioritizr solution — run_minpatch","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"main function applies MinPatch algorithm prioritizr solution ensure protected areas meet minimum size thresholds. function uses prioritizr summary functions possible reduce code duplication ensure consistency prioritizr calculations.","code":""},{"path":"/reference/run_minpatch.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"","code":"run_minpatch( prioritizr_problem, prioritizr_solution, min_patch_size, patch_radius, boundary_penalty = 0, remove_small_patches = TRUE, add_patches = TRUE, whittle_patches = TRUE, solution_column = \"solution_1\", verbose = TRUE )"},{"path":"/reference/run_minpatch.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"prioritizr_problem prioritizr problem object prioritizr_solution solved prioritizr solution object min_patch_size Minimum patch size threshold patch_radius Radius adding new patches boundary_penalty Boundary penalty value (default = 0) remove_small_patches Logical, whether remove small patches (Stage 1, default = TRUE) add_patches Logical, whether add new patches meet targets (Stage 2, default = TRUE) whittle_patches Logical, whether remove unnecessary units (Stage 3, default = TRUE) solution_column Name solution column (default = \"solution_1\") verbose Logical, whether print progress (default = TRUE)","code":""},{"path":"/reference/run_minpatch.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"MinPatch result object enhanced reporting using prioritizr functions","code":""},{"path":"/reference/run_minpatch.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"MinPatch algorithm consists three stages: Remove small patches: Removes patches smaller min_patch_size Add new patches: Adds patches meet conservation targets Whittle patches: Removes unnecessary planning units **Important**: set remove_small_patches = TRUE add_patches = FALSE, algorithm may remove patches without compensating, potentially violating conservation targets. cases, warning issued. Consider using add_patches = TRUE smaller min_patch_size maintain target achievement.","code":""},{"path":"/reference/run_minpatch.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Run MinPatch algorithm on prioritizr solution — run_minpatch","text":"","code":"library(prioritizr) library(sf) library(terra) # Get example data from prioritizr dat <- c(get_sim_pu_raster(), get_sim_features()) %>% as.polygons(dissolve = FALSE, values = TRUE) %>% sf::st_as_sf() %>% dplyr::rename(cost = layer) st_crs(dat) <- NA features = colnames(dat) %>% stringr::str_subset(\"feature_\") # Create prioritizr problem p <- problem(dat, features, cost_column = \"cost\") %>% add_min_set_objective() %>% add_relative_targets(0.17) %>% # 17% of each feature add_binary_decisions() %>% add_default_solver(verbose = FALSE) # Solve problem s <- solve(p) # Apply MinPatch with all stages result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Stage 2: Adding new patches... #> Initial unmet targets: 5 #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Iteration 1 - Unmet targets: 5 #> Found 85 potential patches with scores #> Best score: 0.002500108 for unit 90 #> Added patch centered on unit 90 #> Iteration 2 - Unmet targets: 4 #> Found 76 potential patches with scores #> Best score: 0.002060928 for unit 78 #> Added patch centered on unit 78 #> All conservation targets are now met! #> Stage 3: Removing unnecessary planning units... #> Edge units found: 21 #> Keystone units: 0 #> New keystone units: 0 #> Scoreable units: 21 #> Unit 90 cannot be removed - adding to keystone set #> Edge units found: 20 #> Keystone units: 1 #> New keystone units: 0 #> Scoreable units: 20 #> Unit 81 cannot be removed - adding to keystone set #> Edge units found: 19 #> Keystone units: 2 #> New keystone units: 0 #> Scoreable units: 19 #> Unit 80 cannot be removed - adding to keystone set #> Edge units found: 18 #> Keystone units: 3 #> New keystone units: 0 #> Scoreable units: 18 #> Unit 89 cannot be removed - adding to keystone set #> Edge units found: 17 #> Keystone units: 4 #> New keystone units: 0 #> Scoreable units: 17 #> Unit 73 cannot be removed - adding to keystone set #> Unit 79 cannot be removed - adding to keystone set #> Unit 72 cannot be removed - adding to keystone set #> Unit 88 cannot be removed - adding to keystone set #> Unit 87 cannot be removed - adding to keystone set #> Unit 64 cannot be removed - adding to keystone set #> No more edge units to consider - terminating #> Calculating final statistics... #> MinPatch processing complete! # Apply MinPatch with only Stage 1 and 3 (skip adding patches) result2 <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 0.05, patch_radius = 0.3, add_patches = FALSE ) #> Validating inputs... #> Initializing data structures... #> Calculating boundary matrix (optimized version)... #> Creating patch radius dictionary (optimized)... #> Calculating initial patch statistics... #> Stage 1: Removing small patches... #> Warning: After removing small patches, 5 conservation targets are no longer met. Consider setting add_patches = TRUE to automatically add patches to meet targets, or use a smaller min_patch_size. #> Warning: 5 targets are no longer met after removing small patches #> Unmet feature IDs: 1, 2, 3, 4, 5 #> Stage 2: Skipping addition of new patches... #> Stage 3: Removing unnecessary planning units... #> Edge units found: 5 #> Keystone units: 0 #> New keystone units: 5 #> Scoreable units: 0 #> No units can be removed - all are keystone - terminating #> Calculating final statistics... #> MinPatch processing complete! print_minpatch_summary(result) #> === MinPatch Processing Summary === #> #> Patch Statistics: #> Initial patches: 7 (valid: 1) #> Final patches: 4 (valid: 2) #> Area change: 0.05 (31.2%) #> #> Cost Breakdown: #> Planning unit cost: 4137.80 #> Boundary cost: 0.00 #> Total cost: 4137.80 #> Selected units: 21 #> #> Feature Representation: #> Total features: 5 #> Targets met: 5 #> Targets unmet: 0 #> Mean proportion: 0.236 #> Total shortfall: 0.00 #> #> #> === End Summary ==="},{"path":"/reference/simulated_whittling.html","id":null,"dir":"Reference","previous_headings":"","what":"Simulated whittling to remove unnecessary planning units — simulated_whittling","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"Stage 3 MinPatch: Remove planning units needed meet targets, reduce fragmentation, meet minimum patch size requirements","code":""},{"path":"/reference/simulated_whittling.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"","code":"simulated_whittling(minpatch_data, verbose = TRUE)"},{"path":"/reference/simulated_whittling.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"minpatch_data List containing MinPatch data structures (including prioritizr objects) verbose Logical, whether print progress","code":""},{"path":"/reference/simulated_whittling.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Simulated whittling to remove unnecessary planning units — simulated_whittling","text":"Updated minpatch_data unnecessary units removed","code":""},{"path":"/reference/validate_inputs.html","id":null,"dir":"Reference","previous_headings":"","what":"Validate MinPatch inputs — validate_inputs","title":"Validate MinPatch inputs — validate_inputs","text":"Internal function validate inputs MinPatch algorithm","code":""},{"path":"/reference/validate_inputs.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Validate MinPatch inputs — validate_inputs","text":"","code":"validate_inputs( solution, planning_units, targets, costs, min_patch_size, patch_radius, boundary_penalty )"},{"path":"/reference/validate_inputs.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Validate MinPatch inputs — validate_inputs","text":"solution Binary solution vector planning_units sf object planning units targets data.frame targets costs numeric vector costs min_patch_size minimum patch size patch_radius patch radius adding patches boundary_penalty Boundary penalty value","code":""},{"path":"/reference/validate_inputs.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Validate MinPatch inputs — validate_inputs","text":"NULL (throws errors validation fails)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":null,"dir":"Reference","previous_headings":"","what":"Visualize MinPatch results — plot_minpatch","title":"Visualize MinPatch results — plot_minpatch","text":"Creates simple visualization MinPatch results showing original vs. modified solutions","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"plot_minpatch(minpatch_result, title = \"MinPatch Results\")"},{"path":"/reference/visualize_minpatch_results.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Visualize MinPatch results — plot_minpatch","text":"minpatch_result Result run_minpatch function title Plot title (optional)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Visualize MinPatch results — plot_minpatch","text":"ggplot object (ggplot2 available)","code":""},{"path":"/reference/visualize_minpatch_results.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Visualize MinPatch results — plot_minpatch","text":"","code":"if (FALSE) { # \\dontrun{ # Requires ggplot2 library(ggplot2) # Create example data example_data <- create_example_data(n_units = 25, n_features = 3) # Create prioritizr problem and solve library(prioritizr) p <- problem(example_data$planning_units, cost_column = \"cost\") %>% add_min_set_objective() %>% add_manual_targets(example_data$targets) %>% add_binary_decisions() s <- solve(p) # Run MinPatch result <- run_minpatch( prioritizr_problem = p, prioritizr_solution = s, min_patch_size = 2.0, patch_radius = 1.5 ) # Visualize results plot <- plot_minpatch(result) print(plot) } # }"}]