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,184 @@
1
+ #!/usr/bin/env python3
2
+ # ecological-agent-skills / Copyright (C) 2026 Francisco Diego Barros Barata
3
+ # SPDX-License-Identifier: GPL-3.0-or-later
4
+
5
+ """
6
+ trend_analysis.py
7
+ Mann-Kendall trend + Sen's slope + anomaly detection.
8
+ Usage: python trend_analysis.py <timeseries_csv> <output_dir> [frequency]
9
+ Requires: pandas, numpy, pymannkendall, matplotlib, scipy
10
+ """
11
+ import logging
12
+ import sys
13
+ from datetime import datetime
14
+ from pathlib import Path
15
+
16
+ SKILL_NAME = "environmental-time-series"
17
+ _LOG_DIR = Path("logs")
18
+ _LOG_DIR.mkdir(parents=True, exist_ok=True)
19
+ _log_file = _LOG_DIR / f"skill_{SKILL_NAME}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
20
+ logging.basicConfig(
21
+ level=logging.INFO,
22
+ format="[%(asctime)s] [%(levelname)s] [" + SKILL_NAME + "] %(message)s",
23
+ datefmt="%Y-%m-%d %H:%M:%S",
24
+ handlers=[
25
+ logging.StreamHandler(sys.stdout),
26
+ logging.FileHandler(_log_file, encoding="utf-8"),
27
+ ],
28
+ )
29
+ logger = logging.getLogger(SKILL_NAME)
30
+
31
+ def log_step(n: int, desc: str) -> None:
32
+ logger.info("-- STEP %d: %s", n, desc)
33
+
34
+ def log_decision(var: str, val, why: str) -> None:
35
+ logger.info("DECISION | %s = %s | %s", var, val, why)
36
+
37
+ import numpy as np
38
+ import pandas as pd
39
+ import matplotlib.pyplot as plt
40
+ from scipy import stats
41
+
42
+ try:
43
+ import pymannkendall as mk
44
+ HAS_MK = True
45
+ except ImportError:
46
+ HAS_MK = False
47
+ logger.warning("pymannkendall not installed. Falling back to linear regression. pip install pymannkendall")
48
+
49
+
50
+ def seasonal_decompose_simple(values, freq):
51
+ """Simple additive seasonal decomposition."""
52
+ n = len(values)
53
+ trend = pd.Series(values).rolling(window=freq, center=True, min_periods=1).mean().values
54
+ detrended = values - trend
55
+ seasonal = np.array([np.nanmean(detrended[i::freq]) for i in range(freq)])
56
+ seasonal_full = np.tile(seasonal, n // freq + 1)[:n]
57
+ remainder = values - trend - seasonal_full
58
+ return trend, seasonal_full, remainder
59
+
60
+ def compute_anomalies(values, baseline_n):
61
+ mu = np.nanmean(values[:baseline_n])
62
+ sd = np.nanstd(values[:baseline_n])
63
+ return (values - mu) / (sd + 1e-10)
64
+
65
+ def main():
66
+ ts_file = sys.argv[1] if len(sys.argv) > 1 else "data/ndvi_series.csv"
67
+ output_dir = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("outputs/timeseries")
68
+ freq = int(sys.argv[3]) if len(sys.argv) > 3 else 12
69
+ output_dir.mkdir(parents=True, exist_ok=True)
70
+
71
+ log_decision("ts_file", ts_file, "Input time series CSV")
72
+ log_decision("freq", freq, "Expected seasonal frequency (12 = monthly annual cycle)")
73
+ log_decision("output_dir", str(output_dir), "Directory for trend analysis outputs")
74
+
75
+ if not Path(ts_file).exists():
76
+ logger.error(
77
+ "Input nao encontrado: %s\n"
78
+ " Causa provavel: passo anterior nao concluiu.\n"
79
+ " Skill anterior que deveria ter produzido este input: geoprocessing-for-ecology",
80
+ ts_file
81
+ )
82
+ sys.exit(1)
83
+
84
+ try:
85
+ log_step(1, "Loading time series data")
86
+ dat = pd.read_csv(ts_file)
87
+ val_col = "value" if "value" in dat.columns else dat.columns[-1]
88
+ values = dat[val_col].values.astype(float)
89
+ logger.info("Series length: %d | Frequency: %d", len(values), freq)
90
+
91
+ n_nan = int(np.sum(np.isnan(values)))
92
+ if n_nan > 0:
93
+ logger.warning(
94
+ "%d NaN values detected in series. These will be ignored in statistical tests.",
95
+ n_nan
96
+ )
97
+
98
+ log_step(2, "Running trend test (Mann-Kendall or linear regression)")
99
+ # Mann-Kendall
100
+ if HAS_MK:
101
+ res = mk.original_test(values)
102
+ logger.info(
103
+ "Mann-Kendall: tau = %.4f | p = %.4f | slope = %.6f/obs",
104
+ res.Tau, res.p, res.slope
105
+ )
106
+ log_decision("trend_method", "Mann-Kendall",
107
+ "Preferred non-parametric test for monotonic trends in ecological series")
108
+ trend_df = pd.DataFrame({"tau": [res.Tau], "p_value": [res.p],
109
+ "sens_slope": [res.slope],
110
+ "trend": [res.trend]})
111
+ trend_df.to_csv(output_dir / "trend_results.csv", index=False)
112
+ else:
113
+ log_decision("trend_method", "linear regression",
114
+ "Fallback — pymannkendall not available")
115
+ slope, intercept, r, p, se = stats.linregress(np.arange(len(values)), values)
116
+ logger.info(
117
+ "Linear regression (MK unavailable): slope = %.6f | p = %.4f", slope, p
118
+ )
119
+
120
+ log_step(3, "Seasonal decomposition")
121
+ # Decomposition
122
+ if len(values) >= 2 * freq:
123
+ trend_comp, seasonal_comp, remainder = seasonal_decompose_simple(values, freq)
124
+ fig, axes = plt.subplots(4, 1, figsize=(10, 10), sharex=True)
125
+ for ax, data, title in zip(axes, [values, trend_comp, seasonal_comp, remainder],
126
+ ["Observed", "Trend", "Seasonal", "Remainder"]):
127
+ ax.plot(data); ax.set_title(title); ax.grid(alpha=0.3)
128
+ plt.suptitle("Time Series Decomposition")
129
+ plt.tight_layout()
130
+ plt.savefig(output_dir / "decomposition_plot.png", dpi=150)
131
+ plt.close()
132
+ logger.info("Decomposition plot saved to: %s", output_dir / "decomposition_plot.png")
133
+ else:
134
+ logger.warning(
135
+ "Series length (%d) < 2 * freq (%d). Skipping seasonal decomposition.",
136
+ len(values), 2 * freq
137
+ )
138
+
139
+ log_step(4, "Computing anomaly Z-scores")
140
+ # Anomalies
141
+ baseline_n = min(freq * 10, len(values) // 2)
142
+ log_decision("baseline_n", baseline_n,
143
+ "First N observations used as anomaly baseline (min of 10 cycles, half series)")
144
+ anomalies = compute_anomalies(values, baseline_n)
145
+ dat["anomaly_z"] = anomalies
146
+
147
+ n_extreme = int(np.sum(np.abs(anomalies) > 2))
148
+ if n_extreme > 0:
149
+ logger.warning(
150
+ "%d observations exceed ±2 SD anomaly threshold — review for data quality or ecological extremes.",
151
+ n_extreme
152
+ )
153
+
154
+ dat.to_csv(output_dir / "anomaly_series.csv", index=False)
155
+
156
+ log_step(5, "Generating anomaly bar plot")
157
+ fig, ax = plt.subplots(figsize=(10, 4))
158
+ ax.bar(range(len(anomalies)), anomalies,
159
+ color=np.where(anomalies < 0, "#d6604d", "#4393c3"), alpha=0.8)
160
+ ax.axhline(-1.5, color="orange", linestyle="--", label="±1.5σ")
161
+ ax.axhline(1.5, color="orange", linestyle="--")
162
+ ax.axhline(-2, color="red", linestyle="--", label="±2σ")
163
+ ax.axhline(2, color="red", linestyle="--")
164
+ ax.set_xlabel("Time step"); ax.set_ylabel("Standardised anomaly (z)")
165
+ ax.set_title(f"Anomalies (baseline = first {baseline_n} obs)")
166
+ ax.legend(); plt.tight_layout()
167
+ plt.savefig(output_dir / "anomaly_plot.png", dpi=150)
168
+ plt.close()
169
+ logger.info("Outputs written to: %s", output_dir)
170
+
171
+ except FileNotFoundError as e:
172
+ logger.error(
173
+ "Input file not found: %s\n"
174
+ " Expected output from: geoprocessing-for-ecology\n"
175
+ " Check that previous step completed.",
176
+ e
177
+ )
178
+ raise
179
+ except Exception as e:
180
+ logger.error("Unexpected error in trend analysis: %s", e)
181
+ raise
182
+
183
+ if __name__ == "__main__":
184
+ main()
@@ -0,0 +1,123 @@
1
+ ---
2
+ name: geoprocessing-for-ecology
3
+ description: "Handles spatial data operations: reprojection, raster stacking, clipping, extraction, and environmental predictor downloads for ecological analyses. Use this skill when the user needs CRS reprojection, raster masking or cropping, spatial extraction, buffer creation, raster resampling, spatial joins, GeoTIFF processing, shapefile operations, WorldClim/CHELSA/ERA5 predictor downloads, GDAL operations, or predictor stack preparation."
4
+ skill_version: 1.0.0
5
+ ---
6
+
7
+ # Skill: geoprocessing-for-ecology
8
+
9
+ **Domain:** Spatial analysis · CRS · Raster · Vector · Extraction
10
+ **Phase:** 1 — Foundation
11
+ **Used by:** run-sdm-study, assess-ecological-impact, build-fire-risk-map, analyze-environmental-change, assess-ecosystem-services
12
+
13
+ ---
14
+
15
+ ## Purpose
16
+
17
+ Guides the agent through spatial data operations needed in quantitative ecology: coordinate reference system management, raster and vector processing, spatial masking, buffer creation, intersection, and extraction of environmental values at occurrence or sample points.
18
+
19
+ ---
20
+
21
+ ## When to Invoke
22
+
23
+ - Reprojecting layers to a common CRS
24
+ - Clipping rasters or shapefiles to a study area
25
+ - Extracting environmental variables at point locations
26
+ - Creating buffers around sites or features
27
+ - Computing landscape metrics from a land cover layer
28
+ - Stacking multi-band rasters for modeling
29
+
30
+ ---
31
+
32
+ ## Inputs
33
+
34
+ | Input | Format | Required |
35
+ |-------|--------|----------|
36
+ | Occurrence / sample points | CSV with lat/lon, SHP, GPKG | Yes |
37
+ | Study area polygon | SHP, GPKG, GeoJSON | Yes |
38
+ | Environmental rasters | GeoTIFF, NetCDF | Yes |
39
+ | Land cover or habitat layer | GeoTIFF, SHP | Optional |
40
+
41
+ ---
42
+
43
+ ## Outputs
44
+
45
+ | Output | Description |
46
+ |--------|-------------|
47
+ | `layers_reprojected/` | All layers in common CRS |
48
+ | `predictors_stack.tif` | Aligned, masked raster stack |
49
+ | `points_with_env.csv` | Points with extracted environmental values |
50
+ | `study_area_buffered.gpkg` | Study area with optional buffer |
51
+ | `spatial_qa_report.md` | CRS audit and alignment report |
52
+
53
+ ---
54
+
55
+ ## Steps
56
+
57
+ ### 1. CRS Audit
58
+ - Identify the CRS of each input layer
59
+ - Define the project CRS (default: EPSG:4326 for global; UTM zone for regional)
60
+ - Reproject all layers to the project CRS
61
+ - Document the CRS choice and rationale
62
+
63
+ ### 2. Extent and Resolution Alignment
64
+ - Define the study area extent from the provided polygon
65
+ - Clip all rasters to the study area extent
66
+ - Resample rasters to a common resolution (define target resolution explicitly)
67
+ - Apply the study area mask to remove cells outside the polygon
68
+
69
+ ### 3. Vector Operations
70
+ - Dissolve or simplify study area polygon if needed
71
+ - Create buffers (specify distance and unit)
72
+ - Perform intersection or spatial join between occurrence points and polygon layers
73
+ - Check for topology errors (self-intersections, gaps)
74
+
75
+ ### 4. Environmental Extraction
76
+ - Extract raster values at occurrence and background/pseudo-absence points
77
+ - Handle NA values (edge cells, masked areas): document strategy
78
+ - Check for spatial autocorrelation in extracted values if relevant
79
+
80
+ ### 5. Raster Stack QA
81
+ - Verify all rasters share the same extent, resolution, CRS, and NA mask
82
+ - Report NA cell counts per layer
83
+ - Visualise layer histograms for anomaly detection
84
+
85
+ ### 6. Generate Outputs
86
+ - Write reprojected layers to `layers_reprojected/`
87
+ - Write stacked predictor raster to `predictors_stack.tif`
88
+ - Write points with environmental values to `points_with_env.csv`
89
+ - Write spatial QA report
90
+
91
+ ---
92
+
93
+ ## Key Decisions to Document
94
+
95
+ - Project CRS (EPSG code)
96
+ - Target raster resolution (and rationale)
97
+ - Resampling method (nearest, bilinear, cubic)
98
+ - NA handling strategy
99
+ - Buffer distance (if used)
100
+
101
+ ---
102
+
103
+ ## Tools and Libraries
104
+
105
+ **R:** `terra`, `sf`, `rgdal`, `raster`, `landscapemetrics`
106
+ **Python:** `rasterio`, `geopandas`, `pyproj`, `rasterstats`, `fiona`
107
+ **CLI:** `GDAL/OGR` (gdalwarp, ogr2ogr, gdal_calc)
108
+
109
+ ---
110
+
111
+ ## Resources
112
+
113
+ - `resources/crs-reference.md` — common CRS codes for South American biomes
114
+ - `resources/resampling-methods.md` — when to use each resampling method
115
+ - `examples/` — example extraction workflows
116
+
117
+ ---
118
+
119
+ ## Notes
120
+
121
+ - Always keep original layers intact; write outputs to separate directories
122
+ - Document the GDAL version used for reproducibility
123
+ - For very large rasters (>4 GB), use tiled/chunked processing
@@ -0,0 +1,32 @@
1
+ # Example Invocation Prompts — geoprocessing-for-ecology
2
+
3
+ ## Stack and Extract
4
+
5
+ ```
6
+ Load skill: geoprocessing-for-ecology
7
+ Task: I have 19 WorldClim v2.1 rasters (bio1–bio19) at 2.5 arcmin resolution
8
+ and a set of jaguar occurrence points (occ_clean.csv).
9
+ Study area: Amazon biome polygon (amazon_biome.shp).
10
+ 1. Reproject everything to EPSG:4326 (already geographic, just check).
11
+ 2. Clip rasters to Amazon extent + 1° buffer.
12
+ 3. Extract bioclim values at occurrence and 10,000 background points.
13
+ 4. Output: predictors_stack.tif, points_with_env.csv.
14
+ ```
15
+
16
+ ## Reprojection and Masking
17
+
18
+ ```
19
+ Load skill: geoprocessing-for-ecology
20
+ Task: Reproject landcover_mapbiomas_2022.tif from SIRGAS2000 (EPSG:4674)
21
+ to WGS84 UTM 22S (EPSG:32722). Then mask to the study area polygon
22
+ (cerrado_boundary.gpkg). Use nearest-neighbour resampling. Target resolution: 30m.
23
+ ```
24
+
25
+ ## Buffer and Intersection
26
+
27
+ ```
28
+ Load skill: geoprocessing-for-ecology
29
+ Task: Create a 5 km buffer around all hydroelectric dam points (dams.shp).
30
+ Intersect with the Atlantic Forest remnant polygons (af_remnants.gpkg).
31
+ Report: total forest area within 5 km of dams (ha), and number of dam-affected patches.
32
+ ```
@@ -0,0 +1,62 @@
1
+ # CRS Reference — South American Biomes
2
+
3
+ ## When to Use Each CRS
4
+
5
+ | Use Case | Recommended CRS | EPSG |
6
+ |----------|----------------|------|
7
+ | Global or continental analysis | WGS 84 Geographic | 4326 |
8
+ | Brazil national (planar, metres) | SIRGAS 2000 / UTM | varies by zone |
9
+ | Area calculations, Amazon biome | SIRGAS 2000 UTM Zone 20S | 31980 |
10
+ | Area calculations, Cerrado | SIRGAS 2000 UTM Zone 22S | 31982 |
11
+ | Area calculations, Atlantic Forest | SIRGAS 2000 UTM Zone 23S | 31983 |
12
+ | Area calculations, Pantanal | SIRGAS 2000 UTM Zone 21S | 31981 |
13
+ | Equal-area, continental South America | South America Albers Equal Area | 102033 |
14
+ | Distance calculations | WGS 84 / World Mercator | 3395 |
15
+ | Remote sensing (MODIS native) | Sinusoidal | 6842 |
16
+ | Landsat / Sentinel (Brazil) | WGS84 UTM zone (varies) | 32718–32724 |
17
+
18
+ ## UTM Zone Reference — Brazil
19
+
20
+ | Zone | Longitude Range | States |
21
+ |------|----------------|--------|
22
+ | 18S (32718) | 72°W – 66°W | Far western Acre |
23
+ | 19S (32719) | 66°W – 60°W | Acre, Amazonas W |
24
+ | 20S (32720) | 60°W – 54°W | Amazonas, Pará W, Rondônia |
25
+ | 21S (32721) | 54°W – 48°W | MT, MS, PA centre |
26
+ | 22S (32722) | 48°W – 42°W | GO, TO, MG W |
27
+ | 23S (32723) | 42°W – 36°W | SP, RJ, ES, MG E |
28
+ | 24S (32724) | 36°W – 30°W | BA, SE, AL coast |
29
+ | 25S (32725) | 30°W – 24°W | Fernando de Noronha |
30
+
31
+ ## Reprojection Commands
32
+
33
+ ### R (terra)
34
+ ```r
35
+ library(terra)
36
+ r <- rast("layer.tif")
37
+ r_proj <- project(r, "EPSG:31982") # Bilinear for continuous; near for categorical
38
+ ```
39
+
40
+ ### Python (rasterio + pyproj)
41
+ ```python
42
+ import rasterio
43
+ from rasterio.warp import reproject, Resampling, calculate_default_transform
44
+
45
+ with rasterio.open("layer.tif") as src:
46
+ transform, width, height = calculate_default_transform(
47
+ src.crs, "EPSG:31982", src.width, src.height, *src.bounds)
48
+ ```
49
+
50
+ ### GDAL CLI
51
+ ```bash
52
+ gdalwarp -t_srs EPSG:31982 -r bilinear input.tif output.tif
53
+ ```
54
+
55
+ ## Resampling Method Guide
56
+
57
+ | Data Type | Method | Note |
58
+ |-----------|--------|------|
59
+ | Continuous (elevation, temperature) | Bilinear | Smooth interpolation |
60
+ | Categorical (land cover, soil class) | Nearest neighbour | Preserves class values |
61
+ | Count or integer | Nearest neighbour or mode | |
62
+ | High-precision DEM | Cubic | Smoother gradients |