ecological-agent-skills 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/AGENT_CONTEXT.md +191 -0
  2. package/CATALOG.md +329 -0
  3. package/LICENSE +692 -0
  4. package/README.md +347 -0
  5. package/bin/install.mjs +168 -0
  6. package/docs/comparison-with-alternatives.md +38 -0
  7. package/docs/global-examples-index.md +103 -0
  8. package/docs/repository-statistics.md +101 -0
  9. package/docs/theoretical-foundations.md +188 -0
  10. package/environment.yaml +106 -0
  11. package/examples/community/arctic_tundra_vegetation_example.md +247 -0
  12. package/examples/community/bird_landuse_example.md +63 -0
  13. package/examples/community/phytoplankton_reservoir_example.md +60 -0
  14. package/examples/community/reef_fish_indopacific_example.md +221 -0
  15. package/examples/impact/baci_road_example.md +57 -0
  16. package/examples/impact/ecosystem_services_atlantic_forest.md +83 -0
  17. package/examples/impact/forest_loss_borneo_timeseries_example.md +225 -0
  18. package/examples/occupancy/puma_camera_example.md +61 -0
  19. package/examples/occupancy/snow_leopard_himalayas_example.md +204 -0
  20. package/examples/reproducible/whittaker_biome_sdm_example.md +406 -0
  21. package/examples/sdm/anteater_cerrado_example.md +69 -0
  22. package/examples/sdm/jaguar_amazon_example.md +80 -0
  23. package/examples/sdm/koala_climate_change_example.md +170 -0
  24. package/examples/sdm/wolf_recolonization_europe_example.md +193 -0
  25. package/package.json +43 -0
  26. package/renv.lock +194 -0
  27. package/skills/SKILL_INDEX.json +1020 -0
  28. package/skills/acoustic-monitoring/SKILL.md +163 -0
  29. package/skills/acoustic-monitoring/examples/example-prompts.md +100 -0
  30. package/skills/acoustic-monitoring/examples/temperate_forest_birds_example.md +285 -0
  31. package/skills/acoustic-monitoring/resources/acoustic-indices-reference.md +93 -0
  32. package/skills/acoustic-monitoring/resources/soundscape-ecology-guide.md +90 -0
  33. package/skills/acoustic-monitoring/resources/species-id-tools-comparison.md +89 -0
  34. package/skills/acoustic-monitoring/scripts/batch_species_detection.py +360 -0
  35. package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.R +235 -0
  36. package/skills/acoustic-monitoring/scripts/compute_acoustic_indices.py +374 -0
  37. package/skills/biostatistics-workbench/SKILL.md +140 -0
  38. package/skills/biostatistics-workbench/examples/example-prompts.md +39 -0
  39. package/skills/biostatistics-workbench/resources/effect-size-reference.md +81 -0
  40. package/skills/biostatistics-workbench/resources/glm-family-link-reference.md +47 -0
  41. package/skills/biostatistics-workbench/resources/test-selection-guide.md +93 -0
  42. package/skills/biostatistics-workbench/scripts/glm_pipeline.R +78 -0
  43. package/skills/biostatistics-workbench/scripts/glm_pipeline.py +210 -0
  44. package/skills/camera-trap-processing/SKILL.md +159 -0
  45. package/skills/camera-trap-processing/examples/example-prompts.md +103 -0
  46. package/skills/camera-trap-processing/examples/leopard_serengeti_example.md +231 -0
  47. package/skills/camera-trap-processing/resources/activity-patterns-reference.md +113 -0
  48. package/skills/camera-trap-processing/resources/camtrapR-workflow-guide.md +130 -0
  49. package/skills/camera-trap-processing/resources/detection-event-definition-guide.md +89 -0
  50. package/skills/camera-trap-processing/scripts/estimate_activity.R +169 -0
  51. package/skills/camera-trap-processing/scripts/process_camtrap_data.R +179 -0
  52. package/skills/camera-trap-processing/scripts/process_camtrap_data.py +192 -0
  53. package/skills/community-ecology-ordination/SKILL.md +133 -0
  54. package/skills/community-ecology-ordination/examples/example-prompts.md +35 -0
  55. package/skills/community-ecology-ordination/resources/dissimilarity-metric-guide.md +53 -0
  56. package/skills/community-ecology-ordination/resources/nmds-interpretation-guide.md +104 -0
  57. package/skills/community-ecology-ordination/scripts/__pycache__/community_analysis.cpython-311.pyc +0 -0
  58. package/skills/community-ecology-ordination/scripts/community_analysis.R +143 -0
  59. package/skills/community-ecology-ordination/scripts/community_analysis.py +231 -0
  60. package/skills/ecological-data-foundation/SKILL.md +129 -0
  61. package/skills/ecological-data-foundation/examples/example-prompts.md +40 -0
  62. package/skills/ecological-data-foundation/resources/coordinate-cleaning-flags.md +66 -0
  63. package/skills/ecological-data-foundation/resources/darwin-core-glossary.md +91 -0
  64. package/skills/ecological-data-foundation/resources/data-citation-guide.md +265 -0
  65. package/skills/ecological-data-foundation/resources/gbif-data-citation-guide.md +193 -0
  66. package/skills/ecological-data-foundation/resources/qa-checklist.md +83 -0
  67. package/skills/ecological-data-foundation/scripts/__pycache__/clean_occurrences.cpython-311.pyc +0 -0
  68. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_ebird.cpython-311.pyc +0 -0
  69. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_inat.cpython-311.pyc +0 -0
  70. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_iucn.cpython-311.pyc +0 -0
  71. package/skills/ecological-data-foundation/scripts/__pycache__/download_from_obis.cpython-311.pyc +0 -0
  72. package/skills/ecological-data-foundation/scripts/clean_occurrences.R +230 -0
  73. package/skills/ecological-data-foundation/scripts/clean_occurrences.py +268 -0
  74. package/skills/ecological-data-foundation/scripts/download_from_ebird.R +251 -0
  75. package/skills/ecological-data-foundation/scripts/download_from_ebird.py +364 -0
  76. package/skills/ecological-data-foundation/scripts/download_from_gbif.R +315 -0
  77. package/skills/ecological-data-foundation/scripts/download_from_gbif.py +407 -0
  78. package/skills/ecological-data-foundation/scripts/download_from_inat.R +238 -0
  79. package/skills/ecological-data-foundation/scripts/download_from_inat.py +304 -0
  80. package/skills/ecological-data-foundation/scripts/download_from_iucn.R +273 -0
  81. package/skills/ecological-data-foundation/scripts/download_from_iucn.py +344 -0
  82. package/skills/ecological-data-foundation/scripts/download_from_obis.R +248 -0
  83. package/skills/ecological-data-foundation/scripts/download_from_obis.py +318 -0
  84. package/skills/ecological-impact-assessment/SKILL.md +123 -0
  85. package/skills/ecological-impact-assessment/examples/example-prompts.md +32 -0
  86. package/skills/ecological-impact-assessment/resources/baci-design-guide.md +55 -0
  87. package/skills/ecological-impact-assessment/resources/fragmentation-metrics-reference.md +86 -0
  88. package/skills/ecological-impact-assessment/resources/pressure-index-template.md +78 -0
  89. package/skills/ecological-impact-assessment/resources/study-design-guide.md +168 -0
  90. package/skills/ecological-impact-assessment/scripts/baci_analysis.R +161 -0
  91. package/skills/ecological-impact-assessment/scripts/fragmentation_analysis.py +141 -0
  92. package/skills/ecological-impact-assessment/scripts/power_analysis_baci.R +274 -0
  93. package/skills/ecosystem-services-assessment/SKILL.md +125 -0
  94. package/skills/ecosystem-services-assessment/examples/example-prompts.md +24 -0
  95. package/skills/ecosystem-services-assessment/resources/es-indicator-reference.md +45 -0
  96. package/skills/ecosystem-services-assessment/resources/invest-parameter-guide.md +86 -0
  97. package/skills/ecosystem-services-assessment/resources/rusle-coefficients.md +88 -0
  98. package/skills/ecosystem-services-assessment/scripts/__pycache__/compute_es.cpython-311.pyc +0 -0
  99. package/skills/ecosystem-services-assessment/scripts/compute_es.py +189 -0
  100. package/skills/ecosystem-services-assessment/scripts/tradeoff_analysis.R +161 -0
  101. package/skills/environmental-time-series/SKILL.md +125 -0
  102. package/skills/environmental-time-series/examples/example-prompts.md +33 -0
  103. package/skills/environmental-time-series/resources/anomaly-indices-reference.md +88 -0
  104. package/skills/environmental-time-series/resources/bfast-parameter-guide.md +69 -0
  105. package/skills/environmental-time-series/scripts/__pycache__/recovery_trajectory.cpython-311.pyc +0 -0
  106. package/skills/environmental-time-series/scripts/__pycache__/trend_analysis.cpython-311.pyc +0 -0
  107. package/skills/environmental-time-series/scripts/recovery_trajectory.R +305 -0
  108. package/skills/environmental-time-series/scripts/recovery_trajectory.py +178 -0
  109. package/skills/environmental-time-series/scripts/trend_analysis.R +192 -0
  110. package/skills/environmental-time-series/scripts/trend_analysis.py +184 -0
  111. package/skills/geoprocessing-for-ecology/SKILL.md +123 -0
  112. package/skills/geoprocessing-for-ecology/examples/example-prompts.md +32 -0
  113. package/skills/geoprocessing-for-ecology/resources/crs-reference.md +62 -0
  114. package/skills/geoprocessing-for-ecology/resources/global-predictor-sources.md +331 -0
  115. package/skills/geoprocessing-for-ecology/resources/resampling-methods.md +57 -0
  116. package/skills/geoprocessing-for-ecology/scripts/__pycache__/download_predictors.cpython-311.pyc +0 -0
  117. package/skills/geoprocessing-for-ecology/scripts/download_predictors.R +239 -0
  118. package/skills/geoprocessing-for-ecology/scripts/download_predictors.py +379 -0
  119. package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.R +224 -0
  120. package/skills/geoprocessing-for-ecology/scripts/stack_and_extract.py +172 -0
  121. package/skills/landscape-connectivity/SKILL.md +170 -0
  122. package/skills/landscape-connectivity/examples/example-prompts.md +96 -0
  123. package/skills/landscape-connectivity/examples/jaguar_mesoamerica_corridor_example.md +271 -0
  124. package/skills/landscape-connectivity/resources/circuitscape-parameter-guide.md +155 -0
  125. package/skills/landscape-connectivity/resources/graph-theory-for-ecology.md +134 -0
  126. package/skills/landscape-connectivity/resources/resistance-surface-guide.md +141 -0
  127. package/skills/landscape-connectivity/scripts/connectivity_analysis.py +387 -0
  128. package/skills/landscape-connectivity/scripts/connectivity_metrics.R +274 -0
  129. package/skills/landscape-connectivity/scripts/resistance_surface.R +239 -0
  130. package/skills/model-validation-and-uncertainty/SKILL.md +131 -0
  131. package/skills/model-validation-and-uncertainty/examples/example-prompts.md +30 -0
  132. package/skills/model-validation-and-uncertainty/resources/extrapolation-risk-guide.md +236 -0
  133. package/skills/model-validation-and-uncertainty/resources/metric-selection-guide.md +52 -0
  134. package/skills/model-validation-and-uncertainty/resources/threshold-selection-guide.md +64 -0
  135. package/skills/model-validation-and-uncertainty/scripts/__pycache__/validate_model.cpython-311.pyc +0 -0
  136. package/skills/model-validation-and-uncertainty/scripts/extrapolation_risk.R +315 -0
  137. package/skills/model-validation-and-uncertainty/scripts/validate_model.py +226 -0
  138. package/skills/model-validation-and-uncertainty/scripts/validate_sdm.R +162 -0
  139. package/skills/occupancy-and-detection/SKILL.md +126 -0
  140. package/skills/occupancy-and-detection/examples/example-prompts.md +33 -0
  141. package/skills/occupancy-and-detection/resources/detection-history-format.md +100 -0
  142. package/skills/occupancy-and-detection/resources/occupancy-study-design.md +47 -0
  143. package/skills/occupancy-and-detection/scripts/__pycache__/occupancy_analysis.cpython-311.pyc +0 -0
  144. package/skills/occupancy-and-detection/scripts/occupancy_analysis.R +160 -0
  145. package/skills/occupancy-and-detection/scripts/occupancy_analysis.py +159 -0
  146. package/skills/population-viability-analysis/SKILL.md +161 -0
  147. package/skills/population-viability-analysis/examples/african_elephant_pva_example.md +266 -0
  148. package/skills/population-viability-analysis/examples/example-prompts.md +95 -0
  149. package/skills/population-viability-analysis/resources/extinction-risk-thresholds.md +128 -0
  150. package/skills/population-viability-analysis/resources/matrix-model-guide.md +139 -0
  151. package/skills/population-viability-analysis/resources/sensitivity-elasticity-reference.md +182 -0
  152. package/skills/population-viability-analysis/scripts/matrix_pva.R +258 -0
  153. package/skills/population-viability-analysis/scripts/pva_analysis.py +442 -0
  154. package/skills/population-viability-analysis/scripts/stochastic_pva.R +353 -0
  155. package/skills/predictive-modeling-best-practices/SKILL.md +136 -0
  156. package/skills/predictive-modeling-best-practices/examples/example-prompts.md +58 -0
  157. package/skills/predictive-modeling-best-practices/resources/collinearity-decision-tree.md +65 -0
  158. package/skills/predictive-modeling-best-practices/resources/sampling-bias-correction.md +267 -0
  159. package/skills/predictive-modeling-best-practices/resources/spatial-cv-guide.md +73 -0
  160. package/skills/predictive-modeling-best-practices/scripts/__pycache__/spatial_cv.cpython-311.pyc +0 -0
  161. package/skills/predictive-modeling-best-practices/scripts/collinearity_check.R +112 -0
  162. package/skills/predictive-modeling-best-practices/scripts/spatial_cv.py +182 -0
  163. package/skills/reproducible-ecology-pipeline/SKILL.md +139 -0
  164. package/skills/reproducible-ecology-pipeline/examples/example-prompts.md +35 -0
  165. package/skills/reproducible-ecology-pipeline/resources/directory-structure-template.md +94 -0
  166. package/skills/reproducible-ecology-pipeline/resources/params-yaml-template.yaml +84 -0
  167. package/skills/reproducible-ecology-pipeline/resources/reproducibility-checklist-template.md +66 -0
  168. package/skills/reproducible-ecology-pipeline/scripts/generate_file_manifest.py +110 -0
  169. package/skills/reproducible-ecology-pipeline/scripts/init_project.sh +53 -0
  170. package/skills/spatial-prioritization/SKILL.md +162 -0
  171. package/skills/spatial-prioritization/examples/biodiversity_hotspot_prioritization_example.md +289 -0
  172. package/skills/spatial-prioritization/examples/example-prompts.md +93 -0
  173. package/skills/spatial-prioritization/resources/cost-surface-reference.md +130 -0
  174. package/skills/spatial-prioritization/resources/marxan-vs-prioritizr-comparison.md +125 -0
  175. package/skills/spatial-prioritization/resources/prioritizr-formulation-guide.md +188 -0
  176. package/skills/spatial-prioritization/resources/representation-targets-guide.md +186 -0
  177. package/skills/spatial-prioritization/scripts/prioritization_sensitivity.R +320 -0
  178. package/skills/spatial-prioritization/scripts/run_prioritization.R +336 -0
  179. package/skills/species-distribution-modeling/SKILL.md +139 -0
  180. package/skills/species-distribution-modeling/examples/example-prompts.md +36 -0
  181. package/skills/species-distribution-modeling/resources/algorithm-comparison.md +25 -0
  182. package/skills/species-distribution-modeling/resources/calibration-area-guide.md +71 -0
  183. package/skills/species-distribution-modeling/resources/climate-scenario-preparation.md +170 -0
  184. package/skills/species-distribution-modeling/resources/maxent-calibration-guide.md +211 -0
  185. package/skills/species-distribution-modeling/resources/sdm-checklist.md +37 -0
  186. package/skills/species-distribution-modeling/scripts/predict_distribution.R +236 -0
  187. package/skills/species-distribution-modeling/scripts/predict_distribution.py +286 -0
  188. package/skills/species-distribution-modeling/scripts/prepare_future_layers.R +351 -0
  189. package/skills/species-distribution-modeling/scripts/project_scenarios.R +220 -0
  190. package/skills/species-distribution-modeling/scripts/run_ensemble_sdm.R +99 -0
  191. package/skills/species-distribution-modeling/scripts/sdm_pipeline.py +318 -0
  192. package/skills/species-distribution-modeling/scripts/tune_maxnet.R +344 -0
  193. package/templates/SKILL_TEMPLATE.md +225 -0
  194. package/templates/checklists/data-submission-checklist.md +38 -0
  195. package/templates/checklists/post-analysis-checklist.md +55 -0
  196. package/templates/checklists/pre-analysis-checklist.md +31 -0
  197. package/templates/prompts/debug-skill.md +47 -0
  198. package/templates/prompts/invoke-skill.md +34 -0
  199. package/templates/prompts/invoke-workflow.md +45 -0
  200. package/templates/reports/technical-report-template.md +80 -0
  201. package/templates/scripts/logger_setup.R +79 -0
  202. package/templates/scripts/logger_setup.py +119 -0
  203. package/templates/scripts/params_loader.R +28 -0
  204. package/templates/scripts/params_loader.py +38 -0
  205. package/workflows/analyze-community-structure/WORKFLOW.md +72 -0
  206. package/workflows/analyze-environmental-change/WORKFLOW.md +73 -0
  207. package/workflows/assess-ecological-impact/WORKFLOW.md +75 -0
  208. package/workflows/assess-ecosystem-services/WORKFLOW.md +68 -0
  209. package/workflows/assess-landscape-connectivity/WORKFLOW.md +84 -0
  210. package/workflows/build-fire-risk-map/WORKFLOW.md +79 -0
  211. package/workflows/produce-technical-report/WORKFLOW.md +113 -0
  212. package/workflows/run-camera-trap-occupancy/WORKFLOW.md +87 -0
  213. package/workflows/run-conservation-prioritization/WORKFLOW.md +89 -0
  214. package/workflows/run-multispecies-screening/WORKFLOW.md +197 -0
  215. package/workflows/run-occupancy-analysis/WORKFLOW.md +74 -0
  216. package/workflows/run-population-viability/WORKFLOW.md +90 -0
  217. package/workflows/run-sdm-study/WORKFLOW.md +99 -0
@@ -0,0 +1,271 @@
1
+ ---
2
+ skill_id: landscape-connectivity
3
+ example_type: full_walkthrough
4
+ taxon: Jaguar (Panthera onca)
5
+ region: Mesoamerican Biological Corridor
6
+ ---
7
+
8
+ # Jaguar Corridor Analysis — Mesoamerican Biological Corridor Walkthrough
9
+
10
+ ## Study Context
11
+
12
+ **Location:** Guatemala–Honduras–Nicaragua corridor, Mesoamerican Biological Corridor (MBC)
13
+ **Objective:** Identify critical habitat patches and movement corridors for jaguars along the MBC; prioritise areas for protection and restoration
14
+ **Input data:**
15
+ - Forest cover 2023 (30-m resolution, derived from Global Forest Watch)
16
+ - Land cover map (11 classes, 30-m resolution)
17
+ - DEM (SRTM 30 m)
18
+ - Road network (OSM)
19
+ - 124 camera trap stations with jaguar detections (occupancy data)
20
+
21
+ ---
22
+
23
+ ## Step 1 — Build Resistance Surface
24
+
25
+ ### Resistance table (jaguar-specific)
26
+
27
+ ```
28
+ data/jaguar_resistance.csv:
29
+ lc_code, resistance, description
30
+ 1, 1, Dense tropical forest
31
+ 2, 3, Secondary forest
32
+ 3, 5, Riparian gallery forest
33
+ 4, 8, Cerrado/savanna
34
+ 5, 15, Shrubland
35
+ 6, 25, Pasture (low density)
36
+ 7, 50, Pasture (high density)
37
+ 8, 80, Paved road
38
+ 9,200, Highway
39
+ 10,500, Urban
40
+ 11, 10, Wetland/swamp
41
+ ```
42
+
43
+ ```bash
44
+ Rscript resistance_surface.R \
45
+ data/landcover_2023_mbc.tif \
46
+ data/jaguar_resistance.csv \
47
+ outputs/resistance/ \
48
+ data/dem_srtm_30m.tif \
49
+ data/roads_osm.shp
50
+ ```
51
+
52
+ **Output statistics:**
53
+
54
+ | Statistic | Value |
55
+ |-----------|-------|
56
+ | Min resistance | 1.0 |
57
+ | Median | 8.3 |
58
+ | Mean | 24.7 |
59
+ | Q95 | 95.4 |
60
+ | Max (capped) | 1000.0 |
61
+
62
+ **Decision:** Highway cells assigned resistance = 200 (not 1000) for this analysis, because jaguars have been documented crossing highways via culverts at night. Decision logged with citation (Quigley & Crawshaw 1992).
63
+
64
+ ---
65
+
66
+ ## Step 2 — Delineate Forest Patches
67
+
68
+ ```r
69
+ suppressPackageStartupMessages(library(terra))
70
+ suppressPackageStartupMessages(library(sf))
71
+
72
+ forest <- rast("data/forest_cover_2023_mbc.tif")
73
+ # Patches: connected forest cells ≥ 500 ha
74
+ patches_r <- patches(forest == 1, directions = 8)
75
+ # Compute patch sizes
76
+ patch_sizes <- freq(patches_r)
77
+ large_patches <- patch_sizes[patch_sizes$count * 0.09 >= 500, ] # 30m² = 0.0009 ha
78
+ forest_patches <- as.polygons(patches_r %in% large_patches$value)
79
+ forest_patches_sf <- st_as_sf(forest_patches)
80
+ forest_patches_sf$area_ha <- as.numeric(st_area(forest_patches_sf)) / 1e4
81
+ ```
82
+
83
+ **Result:** 214 forest patches ≥ 500 ha identified.
84
+ - Median patch area: 1,240 ha
85
+ - Largest patch: 312,000 ha (Maya Biosphere Reserve)
86
+ - Range: 502–312,000 ha
87
+
88
+ ---
89
+
90
+ ## Step 3 — Graph Connectivity Analysis
91
+
92
+ ### Sensitivity analysis across dispersal distances
93
+
94
+ ```bash
95
+ # Jaguar max dispersal: 50–500 km reported; use range 20–80 km
96
+ for dmax in 20000 50000 80000; do
97
+ Rscript connectivity_metrics.R \
98
+ data/forest_patches_500ha.shp \
99
+ outputs/connectivity/dmax_${dmax}/ \
100
+ $dmax \
101
+ area_ha
102
+ done
103
+ ```
104
+
105
+ **Sensitivity results:**
106
+
107
+ | dmax (m) | IIC | PC | n_components | Largest component |
108
+ |----------|-----|----|----|---|
109
+ | 20,000 | 0.0412 | 0.0389 | 18 | 71 patches |
110
+ | 50,000 | 0.0847 | 0.0814 | 7 | 142 patches |
111
+ | 80,000 | 0.1183 | 0.1156 | 3 | 198 patches |
112
+
113
+ **Interpretation:** At all dispersal distances, landscape connectivity is < 0.12 — indicating high fragmentation. The MBC is not functionally connected for jaguars across most of its length.
114
+
115
+ **Decision:** Analysis proceeds with dmax = 50,000 m (50 km), representing conservative mid-range jaguar dispersal (Rabinowitz & Zeller 2010).
116
+
117
+ ### Top patches by dPC
118
+
119
+ ```r
120
+ metrics <- read.csv("outputs/connectivity/dmax_50000/patch_metrics.csv")
121
+ head(metrics[, c("patch_id", "area_ha", "dPC_pct", "BC_norm")], 10)
122
+ ```
123
+
124
+ | patch_id | area_ha | dPC (%) | BC (norm) |
125
+ |----------|---------|---------|-----------|
126
+ | P001 | 312,000 | 18.4 | 0.42 |
127
+ | P017 | 85,200 | 12.1 | 0.38 |
128
+ | P003 | 142,100 | 9.7 | 0.29 |
129
+ | P089 | 8,400 | **7.2** | **0.81** |
130
+ | P122 | 3,200 | 5.1 | 0.76 |
131
+ | P071 | 12,800 | 4.8 | 0.67 |
132
+
133
+ **Key finding:** Patch P089 (8,400 ha) has disproportionately high dPC (7.2%) and betweenness centrality (0.81) relative to its size. It is a **stepping stone** connecting the two largest forest blocks. High BC = critical corridor function.
134
+
135
+ ---
136
+
137
+ ## Step 4 — Circuitscape Current Flow
138
+
139
+ ```r
140
+ source("scripts/run_circuitscape.R")
141
+
142
+ # Use top 20 patches by dPC as focal nodes
143
+ focal_patches <- metrics[1:20, "patch_id"]
144
+ focal_shp <- forest_patches_sf[forest_patches_sf$patch_id %in% focal_patches, ]
145
+ st_write(focal_shp, "data/focal_nodes.shp", delete_dsn = TRUE)
146
+
147
+ cur_map <- run_circuitscape(
148
+ resistance_tif = "outputs/resistance/resistance_combined.tif",
149
+ focal_points_shp = "data/focal_nodes.shp",
150
+ output_dir = "outputs/circuitscape/",
151
+ scenario = "pairwise"
152
+ )
153
+ ```
154
+
155
+ **Pinch point extraction:**
156
+
157
+ ```r
158
+ cur <- rast("outputs/circuitscape/cs_output_cum_curmap.asc")
159
+ q95 <- quantile(values(cur), 0.95, na.rm = TRUE)
160
+ pinch <- cur >= q95
161
+ writeRaster(pinch, "outputs/circuitscape/pinchpoints.tif", overwrite = TRUE)
162
+ # Extract pinch point polygons for reporting
163
+ pinch_poly <- as.polygons(pinch)
164
+ ```
165
+
166
+ **Results:** 23 pinch point clusters identified, totalling ~180 km². Top 5:
167
+
168
+ | Pinch point | Area (km²) | Location | Threat |
169
+ |-------------|-----------|----------|--------|
170
+ | PP01 | 42 | Petén–Alta Verapaz junction | Active deforestation |
171
+ | PP02 | 31 | Río Motagua corridor | Highway CA-9 |
172
+ | PP03 | 18 | Honduras–Nicaragua border | Cattle expansion |
173
+ | PP04 | 12 | Caribbean lowlands Guatemala | Oil palm |
174
+ | PP05 | 8 | Bay Islands bridge | Tourism development |
175
+
176
+ ---
177
+
178
+ ## Step 5 — Scenario Analysis: Corridor Protection
179
+
180
+ **Question:** If PP01 (42 km²) were protected and restored to forest, how much would PC increase?
181
+
182
+ ```r
183
+ # Create scenario patch: add PP01 as new forest patch
184
+ pp01 <- data.frame(
185
+ patch_id = "PP01_restored",
186
+ x = centroid_x, y = centroid_y,
187
+ area_ha = 4200
188
+ )
189
+ patches_scenario <- rbind(patches_original, pp01)
190
+
191
+ # Recompute connectivity
192
+ python_cmd <- sprintf(
193
+ "python connectivity_analysis.py data/patches_scenario.csv outputs/scenario/ --dmax 50000"
194
+ )
195
+ system(python_cmd)
196
+
197
+ pc_scenario <- read.csv("outputs/scenario/landscape_summary.csv")
198
+ pc_baseline <- 0.0814
199
+ pc_new <- pc_scenario$value[pc_scenario$metric == "PC"]
200
+ cat(sprintf("PC improvement: %.4f → %.4f (+%.1f%%)\n",
201
+ pc_baseline, pc_new, (pc_new - pc_baseline) / pc_baseline * 100))
202
+ ```
203
+
204
+ **Result:** Restoring PP01 increases PC from 0.0814 to 0.1021 (+25.4%). This is the single highest-leverage restoration action in the landscape.
205
+
206
+ ---
207
+
208
+ ## Step 6 — Final Outputs
209
+
210
+ ```
211
+ outputs/
212
+ ├── resistance/
213
+ │ ├── resistance_lc.tif
214
+ │ ├── resistance_combined.tif # LC + slope + road proximity
215
+ │ └── resistance_stats.csv
216
+ ├── connectivity/
217
+ │ └── dmax_50000/
218
+ │ ├── patch_metrics.csv # 214 patches, ranked by dPC
219
+ │ ├── landscape_summary.csv
220
+ │ └── connectivity_graph.png
221
+ ├── circuitscape/
222
+ │ ├── cs_output_cum_curmap.asc # Cumulative current flow
223
+ │ ├── pinchpoints.tif # Top 5% current cells
224
+ │ └── pinchpoints.shp # Polygon pinch points
225
+ └── scenario/
226
+ └── landscape_summary.csv # PC after PP01 restoration
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Summary Table
232
+
233
+ | Metric | Baseline | PP01 restored | Change |
234
+ |--------|---------|--------------|--------|
235
+ | IIC | 0.0847 | 0.1094 | +29.2% |
236
+ | PC | 0.0814 | 0.1021 | +25.4% |
237
+ | n components | 7 | 6 | −1 |
238
+ | Largest component (patches) | 142 | 158 | +16 |
239
+
240
+ ---
241
+
242
+ ## Decision Log
243
+
244
+ ```yaml
245
+ - date: 2025-01-20
246
+ skill_id: landscape-connectivity
247
+ decision: "Highway resistance set to 200, not 1000"
248
+ rationale: "Culvert crossings documented; Quigley & Crawshaw (1992)"
249
+ outputs: ["outputs/resistance/resistance_combined.tif"]
250
+
251
+ - date: 2025-01-21
252
+ skill_id: landscape-connectivity
253
+ decision: "Dispersal distance set to 50 km for main analysis"
254
+ rationale: "Conservative mid-range; sensitivity shows IIC robust ±20% across 20-80km"
255
+ outputs: ["outputs/connectivity/dmax_50000/landscape_summary.csv"]
256
+
257
+ - date: 2025-01-22
258
+ skill_id: landscape-connectivity
259
+ decision: "Patch P089 flagged as critical stepping stone"
260
+ rationale: "High BC (0.81) despite small area; bridges components 3 and 4"
261
+ outputs: ["outputs/connectivity/dmax_50000/patch_metrics.csv"]
262
+ ```
263
+
264
+ ---
265
+
266
+ ## References
267
+
268
+ - Rabinowitz, A. & Zeller, K.A. (2010). A range-wide model of landscape connectivity and conservation for the jaguar. *Biological Conservation*, 143(4), 939–945. DOI: 10.1016/j.biocon.2010.01.002
269
+ - Pascual-Hortal, L. & Saura, S. (2006). Comparison and development of new graph-based landscape connectivity indices. *Landscape Ecology*, 21(7), 959–967. DOI: 10.1007/s10980-006-0013-z
270
+ - McRae, B.H. et al. (2008). Using circuit theory to model connectivity in ecology. *Ecology*, 89(10), 2712–2724. DOI: 10.1890/07-1861.1
271
+ - Zeller, K.A. et al. (2012). Estimating landscape resistance to movement. *Landscape Ecology*, 27(6), 777–797. DOI: 10.1007/s10980-012-9737-0
@@ -0,0 +1,155 @@
1
+ ---
2
+ resource_id: circuitscape-parameter-guide
3
+ skill_id: landscape-connectivity
4
+ ---
5
+
6
+ # Circuitscape Parameter Guide
7
+
8
+ ## What Circuitscape Models
9
+
10
+ Circuitscape applies circuit theory to landscape connectivity. Each raster cell is a resistor; current flows from source to ground nodes. **High current = high movement probability.** Unlike least-cost paths (single path), Circuitscape identifies all possible movement paths simultaneously, making it robust to barrier uncertainty.
11
+
12
+ **When to use Circuitscape:**
13
+ - Species with exploratory or random-walk dispersal (amphibians, many invertebrates)
14
+ - Gene flow modelling (isolation by resistance)
15
+ - Identifying multiple corridors and bottlenecks simultaneously
16
+
17
+ **When least-cost path may be preferred:**
18
+ - Species with directed, optimal-path movement (large carnivores following trails)
19
+ - Fine-resolution analysis where single corridors are sufficient
20
+
21
+ ---
22
+
23
+ ## Key Parameters
24
+
25
+ | Parameter | Options | Recommended default | Effect |
26
+ |-----------|---------|---------------------|--------|
27
+ | `scenario` | `pairwise`, `one-to-all`, `all-to-one` | `pairwise` | Analysis mode |
28
+ | `data_type` | `raster`, `network` | `raster` | Input format |
29
+ | `resistance_file` | path to .asc/.tif | — | Resistance surface |
30
+ | `point_file` | path to focal nodes .shp | — | Source/destination points |
31
+ | `write_cum_cur_map_only` | True/False | True (pairwise sums) | Output cumulative vs all pairwise maps |
32
+ | `log_transform_maps` | True/False | True | Log-scale current maps easier to visualise |
33
+ | `compress_grids` | True/False | True | Reduce output file size |
34
+ | `solver` | `cg+amg`, `cholmod` | `cg+amg` | Large rasters; cholmod for small/medium |
35
+ | `max_parallel` | int | n_cores - 1 | Parallelisation |
36
+
37
+ ---
38
+
39
+ ## Running Circuitscape from R (via System Call)
40
+
41
+ ```r
42
+ # Usage: source("run_circuitscape.R")
43
+ suppressPackageStartupMessages(library(terra))
44
+
45
+ run_circuitscape <- function(resistance_tif, focal_points_shp, output_dir,
46
+ scenario = "pairwise", solver = "cg+amg") {
47
+ dir.create(output_dir, recursive = TRUE, showWarnings = FALSE)
48
+
49
+ # Export resistance as .asc (Circuitscape requires ASCII grid or GeoTIFF)
50
+ res <- rast(resistance_tif)
51
+ asc_path <- file.path(output_dir, "resistance.asc")
52
+ writeRaster(res, asc_path, filetype = "AAIGrid", overwrite = TRUE)
53
+
54
+ # Write Circuitscape INI configuration
55
+ ini_path <- file.path(output_dir, "cs_config.ini")
56
+ ini_content <- sprintf(
57
+ "[circuitscape options]
58
+ scenario = %s
59
+ data_type = raster
60
+ resistance_file = %s
61
+ point_file = %s
62
+ output_file = %s
63
+ write_cum_cur_map_only = True
64
+ log_transform_maps = True
65
+ compress_grids = True
66
+ solver = %s
67
+ max_parallel = %d
68
+ ",
69
+ scenario,
70
+ normalizePath(asc_path),
71
+ normalizePath(focal_points_shp),
72
+ normalizePath(file.path(output_dir, "cs_output")),
73
+ solver,
74
+ max(1L, parallel::detectCores() - 1L)
75
+ )
76
+ writeLines(ini_content, ini_path)
77
+
78
+ # Call Circuitscape (must be installed and on PATH)
79
+ cmd <- sprintf("cs_run.py %s", shQuote(ini_path))
80
+ ret <- system(cmd)
81
+ if (ret != 0) warning("Circuitscape returned non-zero exit code: ", ret)
82
+ return(file.path(output_dir, "cs_output_cum_curmap.asc"))
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Interpreting Circuitscape Output Maps
89
+
90
+ | Output file | What it shows |
91
+ |-------------|--------------|
92
+ | `*_cum_curmap.asc` | Summed current across all pairwise flows — identifies corridors |
93
+ | `*_resistances.out` | Effective resistance between each pair of nodes |
94
+ | `*_curmap_X_Y.asc` | Current map for specific node pair X→Y |
95
+
96
+ ### Post-processing current map in R
97
+
98
+ ```r
99
+ suppressPackageStartupMessages(library(terra))
100
+
101
+ cur <- rast("outputs/circuitscape/cs_output_cum_curmap.asc")
102
+
103
+ # Log-scale for visualisation
104
+ cur_log <- log1p(cur)
105
+
106
+ # Identify pinch points: cells with high current in narrow flow paths
107
+ # Threshold: top 5% of current values
108
+ q95 <- quantile(values(cur_log), 0.95, na.rm = TRUE)
109
+ pinchpoints <- cur_log >= q95
110
+ writeRaster(pinchpoints, "outputs/circuitscape/pinchpoints.tif", overwrite = TRUE)
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Choosing Focal Nodes
116
+
117
+ | Scenario | Recommended focal nodes |
118
+ |----------|------------------------|
119
+ | Cross-landscape connectivity | Large core habitat patches (> 100 ha) |
120
+ | Corridor between two areas | Source and destination patches only |
121
+ | Full landscape assessment | All patches > minimum size threshold |
122
+ | Genetic sampling sites | Population sampling locations |
123
+
124
+ **Rule:** Keep focal node count ≤ 50 for pairwise scenario on standard hardware. More nodes → O(n²) compute time.
125
+
126
+ ---
127
+
128
+ ## Computational Considerations
129
+
130
+ | Raster resolution | Focal nodes | Typical runtime | Solver recommendation |
131
+ |------------------|-------------|----------------|----------------------|
132
+ | 30 m, 10×10 km extent | 20 | 2–5 min | cg+amg |
133
+ | 30 m, 100×100 km extent | 50 | 30–90 min | cg+amg |
134
+ | 10 m, 50×50 km extent | 30 | 2–8 h | cholmod or HPC |
135
+ | 1 m, any extent | — | Not feasible | Resample to ≥ 10 m |
136
+
137
+ **Tip:** Resample resistance raster to the coarsest resolution that still captures key barriers (e.g., roads, rivers). Test with 100 m resolution first; refine if necessary.
138
+
139
+ ---
140
+
141
+ ## Pitfalls
142
+
143
+ - **Current maps conflate corridors with high-permeability areas:** High current can result from many paths OR from a single wide, low-resistance path. Always check raster context (road maps, imagery) around high-current cells.
144
+ - **Focal nodes inside high-resistance cells:** Circuitscape places current sources at node locations. If a node is on a road (high resistance), effective resistance will be artificially inflated. Snap nodes to nearest low-resistance cell.
145
+ - **Ignoring NoData handling:** NoData cells are treated as barriers. Ensure NoData correctly represents barriers (not missing data). Fill missing cells with average neighbourhood resistance before analysis.
146
+ - **Comparing Circuitscape between landscapes without standardisation:** Cumulative current scales with number of focal nodes and landscape size. Only compare effective resistance values, not raw current maps, across landscapes.
147
+ - **Using Circuitscape for directed movement:** Circuitscape is symmetric. For strongly directional dispersal (stream-mediated, prevailing winds), use directional least-cost models instead.
148
+
149
+ ---
150
+
151
+ ## References
152
+
153
+ - McRae, B.H., Dickson, B.G., Keitt, T.H. & Shah, V.B. (2008). Using circuit theory to model connectivity in ecology, evolution, and conservation. *Ecology*, 89(10), 2712–2724. DOI: 10.1890/07-1861.1
154
+ - Shah, V.B. & McRae, B.H. (2008). Circuitscape: a tool for landscape ecology. *Proceedings of the 7th Python in Science Conference*, 62–65.
155
+ - Dickson, B.G. et al. (2019). Informing strategic efforts to expand and connect protected areas using a model of ecological flow, with application to the western United States. *Conservation Letters*, 12(3), e12647. DOI: 10.1111/conl.12647
@@ -0,0 +1,134 @@
1
+ ---
2
+ resource_id: graph-theory-for-ecology
3
+ skill_id: landscape-connectivity
4
+ ---
5
+
6
+ # Graph Theory for Landscape Ecology
7
+
8
+ ## Core Connectivity Metrics
9
+
10
+ | Metric | Formula | Scale | Interpretation | Requires |
11
+ |--------|---------|-------|----------------|---------|
12
+ | **IIC** (Integral Index of Connectivity) | (1/A²) Σ (aᵢ × aⱼ) / (1 + nᵢⱼ) | 0–1 | Landscape-level binary connectivity | Dispersal threshold |
13
+ | **PC** (Probability of Connectivity) | (1/A²) Σ pᵢⱼ* × aᵢ × aⱼ | 0–1 | Landscape-level probabilistic connectivity | Dispersal function |
14
+ | **dIIC** (patch contribution to IIC) | [(IIC − IICremove) / IIC] × 100 | % | Importance of patch i to overall IIC | — |
15
+ | **dPC** (patch contribution to PC) | [(PC − PCremove) / PC] × 100 | % | Importance of patch i to overall PC | — |
16
+ | **BC** (Betweenness Centrality) | fraction of shortest paths through node i | 0–1 | Stepping stone / corridor value | — |
17
+ | **EC** (Eigenvalue Centrality) | dominant eigenvector component | 0–∞ | Well-connected patches in dense cluster | — |
18
+
19
+ **Landscape area A:** total study area (same units as patch areas).
20
+
21
+ ---
22
+
23
+ ## When to Use IIC vs PC
24
+
25
+ | Condition | Recommended metric | Reason |
26
+ |-----------|--------------------|--------|
27
+ | Dispersal threshold unknown | IIC | Binary; only requires yes/no connection |
28
+ | Dispersal probability decay known | PC | Incorporates full movement function |
29
+ | Comparing two landscapes | dIIC, dPC | Relative patch importance is comparable |
30
+ | Identifying stepping stones | BC | Patches with high BC are corridor nodes |
31
+ | Data on gene flow or mark-recapture | PC | Can calibrate pᵢⱼ* with empirical data |
32
+
33
+ ---
34
+
35
+ ## Computing IIC and dPC in R (igraph)
36
+
37
+ ```r
38
+ # Usage: source("connectivity_metrics.R")
39
+ suppressPackageStartupMessages(library(igraph))
40
+ suppressPackageStartupMessages(library(sf))
41
+
42
+ # Patches: sf polygon layer with attribute 'area_ha'
43
+ # Dispersal threshold: dmax in map units (e.g., metres)
44
+
45
+ compute_iic <- function(patches, dmax) {
46
+ n <- nrow(patches)
47
+ A <- sum(patches$area_ha)
48
+ coords <- st_centroid(patches) %>% st_coordinates()
49
+ dist_mat <- as.matrix(dist(coords))
50
+
51
+ # Binary adjacency: connected if distance < dmax
52
+ adj <- (dist_mat < dmax) * 1
53
+ diag(adj) <- 0
54
+ g <- graph_from_adjacency_matrix(adj, mode = "undirected")
55
+
56
+ # Shortest paths (hop count)
57
+ sp <- distances(g, algorithm = "bfs")
58
+
59
+ IIC_num <- 0
60
+ for (i in seq_len(n)) {
61
+ for (j in seq_len(n)) {
62
+ nij <- sp[i, j]
63
+ if (is.finite(nij)) {
64
+ IIC_num <- IIC_num +
65
+ (patches$area_ha[i] * patches$area_ha[j]) / (1 + nij)
66
+ }
67
+ }
68
+ }
69
+ IIC <- IIC_num / A^2
70
+ return(IIC)
71
+ }
72
+
73
+ # Patch importance: dIIC
74
+ compute_diic <- function(patches, dmax) {
75
+ IIC_full <- compute_iic(patches, dmax)
76
+ diic_vec <- numeric(nrow(patches))
77
+ for (i in seq_len(nrow(patches))) {
78
+ IIC_i <- compute_iic(patches[-i, ], dmax)
79
+ diic_vec[i] <- (IIC_full - IIC_i) / IIC_full * 100
80
+ }
81
+ patches$dIIC <- diic_vec
82
+ return(patches)
83
+ }
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Interpreting dPC Values
89
+
90
+ | dPC (%) | Patch importance | Recommended action |
91
+ |---------|-----------------|-------------------|
92
+ | > 10 | Critical | Highest protection priority; any loss severely disrupts connectivity |
93
+ | 5–10 | High | Priority for protection or restoration buffer |
94
+ | 1–5 | Moderate | Monitor; stepping-stone function likely |
95
+ | < 1 | Low | May contribute if adjacent patches are lost |
96
+ | 0 | Isolated | Not connected within dispersal distance; restoration needed first |
97
+
98
+ ---
99
+
100
+ ## Dispersal Distance Sensitivity Analysis
101
+
102
+ When the species dispersal distance is uncertain, run connectivity across a range:
103
+
104
+ ```r
105
+ dmax_values <- c(500, 1000, 2000, 5000) # metres
106
+ results <- lapply(dmax_values, function(d) {
107
+ iic <- compute_iic(patches, dmax = d)
108
+ data.frame(dmax = d, IIC = iic)
109
+ })
110
+ sens_df <- dplyr::bind_rows(results)
111
+ plot(sens_df$dmax, sens_df$IIC, type = "b",
112
+ xlab = "Dispersal distance (m)", ylab = "IIC",
113
+ main = "Connectivity sensitivity to dispersal distance")
114
+ ```
115
+
116
+ **Rule:** If IIC changes < 10% across the plausible dmax range → results are robust to dispersal distance uncertainty.
117
+
118
+ ---
119
+
120
+ ## Pitfalls
121
+
122
+ - **Euclidean vs cost distance:** Graph edges based on straight-line distance ignore barriers (roads, rivers). Use cost distance for species with limited matrix permeability.
123
+ - **Patch definition:** Patches defined at too coarse a resolution inflate IIC by merging sub-patches that are not functionally connected.
124
+ - **Island patches:** Isolated patches (not connected to any other patch) contribute only their intra-patch value to IIC/PC. Report isolation separately.
125
+ - **Directed vs undirected graphs:** Most landscape connectivity models assume undirected movement. For rivers or wind-pollinated species, use directed graphs.
126
+ - **Comparing across study areas:** IIC and PC scale with A². Always normalise by landscape area when comparing sites.
127
+
128
+ ---
129
+
130
+ ## References
131
+
132
+ - Pascual-Hortal, L. & Saura, S. (2006). Comparison and development of new graph-based landscape connectivity indices. *Landscape Ecology*, 21(7), 959–967. DOI: 10.1007/s10980-006-0013-z
133
+ - Saura, S. & Torné, J. (2009). Conefor Sensinode 2.2: A software package for quantifying the importance of habitat patches for landscape connectivity. *Environmental Modelling & Software*, 24(1), 135–139. DOI: 10.1016/j.envsoft.2008.05.005
134
+ - Urban, D. & Keitt, T. (2001). Landscape connectivity: a graph-theoretic perspective. *Ecology*, 82(5), 1205–1218. DOI: 10.1890/0012-9658(2001)082[1205:LCAGTP]2.0.CO;2