---
title: "Step 3: Occurrences-to-biome classification"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Step 3: Occurrences-to-biome classification}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
Sys.setenv(OPENBLAS_NUM_THREADS = "1")
Sys.setenv(OMP_NUM_THREADS      = "1")
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(biomes)
data(biomes_example)

run_raster <- isTRUE(as.logical(Sys.getenv("NOT_CRAN", "false")))
if (run_raster) {
  run_raster <- tryCatch({ biomes_download(quiet = TRUE); TRUE },
                         error = function(e) FALSE)
}
```

# Goal

With a biome scheme chosen in [Step 2](step2-choosing-a-biome-scheme.html),
`biomes_classify()` assigns **one biome class per occurrence record**. You select the
scheme by its **biome scheme number** (1-31), the same number `biomes_rank()` returns
as the best scheme.

> **Terms.** *Classifying* here means assigning each **occurrence record** to a
> **biome class** (e.g. *savanna*) of the chosen **biome scheme** (identified by its
> biome scheme number).

---

# 1. Classify occurrence records into biome classes

`biomes_classify()` takes a table of points (or an `sf` / `SpatVector`) and returns
the **input data with the biome-class assignment appended on the right**. Pick the
scheme with the `scheme` argument; you never handle `SpatRaster` objects yourself.

```{r, eval = run_raster}
classified <- biomes_classify(biomes_example, scheme = 1)
head(classified)
```

A new column `Biome_Inventory_layer_01_name` has been added (the column names carry
the raster layer names of the packaged stack). The appended columns use the suffixes
`_value` (raster code) and `_name` (biome-class name). Records that fall **outside**
every biome class of a scheme (e.g. coastal records or small islands missing from a
coarse map) are, by default, labelled `"no_biome"` rather than dropped, so the counts
stay complete:

```{r, eval = run_raster}
table(classified$Biome_Inventory_layer_01_name, useNA = "ifany")
```

Handling off-map records **explicitly and identically across schemes** matters,
because the amount and spatial pattern of unassigned records differs between schemes,
and is itself one of the ranking criteria in Step 2.

---

# 2. Common variations

```{r, eval = run_raster}
# Several schemes at once, one column per scheme
biomes_classify(biomes_example, scheme = c(1, 25)) |> head(3)

# Keep both the raster value and the biome-class name
biomes_classify(biomes_example, scheme = 1, value = "both") |> head(3)

# Return only the classification columns (drop the input)
biomes_classify(biomes_example, scheme = 1, append = FALSE) |> head(3)

# Keep NA for off-map points instead of the "no_biome" label
class_na <- biomes_classify(biomes_example, scheme = 1, na = NA)
sum(is.na(class_na$Biome_Inventory_layer_01_name))
```

For a scheme outside the packaged stack, pass your own single-layer
`terra::SpatRaster` via `biome =` instead of a scheme number.

---

# Next

Your records now carry a biome-class assignment. Continue with
[Step 4: Output and visualisation](step4-output-and-visualisation.html) to tabulate and
map them.
