Overview
sight_fit_model_id() accepts a data
parameter that lets you pass your own observation data instead of
fetching from the database. This is useful when you need to: - Run
models on modified or filtered observations - Test estimation with
synthetic data - Reproduce results with a known dataset
There are two estimation paths depending on the model type:
- Abundance estimation uses a sightability model to correct for detection bias and extrapolate across the survey design
- Ratio estimation computes demographic ratios (e.g., fawn:doe) from composition survey counts
Before building custom data you need to discover the right IDs for your species, survey type, analysis unit, strata, and model. IDs are not stable across projects, so always use the lookup functions rather than hardcoding values.
Discovering your parameters
Species
# Browse all species in the project
lkup_species()
# Get the ID for a specific species
species_id <- lkup_species_id("Mule Deer")Survey types
# List survey types available for this species
lkup_survey_type(species_id = species_id)
# Get the ID for a sightability survey
survey_type_id <- lkup_survey_type_id(
"Sightability",
species_id = species_id
)Analysis units (DAUs)
# List DAUs for this species
lkup_dau(species_id = species_id)
# Get a specific DAU ID
dau_id <- lkup_dau_id(
"North Converse 755",
species_id = species_id
)Strata
# List strata for a species + survey type combination
lkup_strata(
species_id = species_id,
survey_type_name = "Sightability"
)
# Returns id, name pairs (e.g., 17 = "High", 19 = "Low")
# stratum_id = 0 or NA maps to the "Other" stratum (non-extrapolating)Models
# Find models available for your species + survey type
models <- sight_read_model(
species = "Mule Deer",
survey_type = "Sightability"
)
print(models)
# Pick the model you need
model_id <- models$id[1]
# Check the model's metadata to understand its estimation method
model <- sight_read_model(id = model_id)
model$metadata[[1]]
# $method tells you the estimation approach:
# "sightability" - classical Wong estimator (requires covariates)
# "cochran" - Cochran ratio estimator
# "quasibinomial"- quasi-binomial GLM variance
# For sightability models, inspect the covariates
betas <- sight_read_betas_id(
model_id = model_id,
includes = "covar"
)
print(betas)
# Shows which covariates the model uses (activity, vegetation_type,
# snow_percentage, group_size) and their coded levelsSubunits
# List subunits within a DAU
spdgt.core::lkup_read_subunit(dau_id = dau_id)
# Returns id, management_unit_id, name, sort_orderData schema reference
The data parameter expects a tibble that matches the
structure of prepared survey data. The columns fall into four
groups:
Context columns
The API extracts these to populate response metadata. Each column should contain a single unique value across all rows.
| Column | Type | Description |
|---|---|---|
species_id |
integer | Species identifier |
bio_year |
integer | Biological year (e.g., 2024) |
analysis_unit_id |
integer | Analysis unit (DAU) identifier |
survey_type_id |
integer | Survey type identifier |
Observation columns
These drive the estimation calculations.
| Column | Type | Description |
|---|---|---|
subunit_id |
integer | Subunit (survey unit) identifier |
stratum_id |
integer | Stratum identifier (0 = “Other”) |
is_selected |
logical | Whether the subunit was selected in the design |
is_surveyed |
logical | Whether the subunit was actually surveyed |
total |
integer | Total animal count |
males |
integer | Male count |
females |
integer | Female count |
youngs |
integer | Young-of-year count |
unclass |
integer | Unclassified count |
The demographic count column names vary by survey type. Use
sight_read_survey_cols_id() to discover the correct names
for your survey type.
Covariate columns (sightability models only)
Required when the model method is "sightability". Values
must match the coded levels in the model’s betas table (see
sight_read_betas_id()).
| Column | Type | Description |
|---|---|---|
activity |
integer | Activity code (e.g., 1 = Moving, 2 = Standing) |
vegetation_type |
integer | Vegetation code (e.g., 1 = Conifer, 2 = Grassland) |
snow_percentage |
integer | Snow cover percentage (0–100) |
Spatial columns
| Column | Type | Description |
|---|---|---|
management_unit_id |
integer | GMU identifier (from subunit lookup) |
Optional columns
| Column | Type | Description |
|---|---|---|
metadata |
list | Empty list() per row; only needed if
entry-column-mapping transforms were applied |
Example 1: Abundance estimation (sightability model)
This example builds a synthetic 20-row tibble and passes it to
sight_fit_model_id() with a sightability model.
Discover IDs
species_id <- lkup_species_id("Mule Deer")
survey_type_id <- lkup_survey_type_id(
"Sightability",
species_id = species_id
)
dau_id <- lkup_dau_id(
"North Converse 755",
species_id = species_id
)
# Find available models for this species + survey type
models <- sight_read_model(
species = "Mule Deer",
survey_type = "Sightability"
)
model_id <- models$id[1]
# Inspect betas to learn covariate coding
betas <- sight_read_betas_id(
model_id = model_id,
includes = "covar"
)
print(betas)
# e.g., activity: 1=Moving, 2=Standing, 3=Bedded, 4=Running
# vegetation_type: 1=Conifer, 2=Grassland/Open
# snow_percentage: continuous (0-100)
# Get strata
strata <- lkup_strata(
species_id = species_id,
survey_type_name = "Sightability"
)
print(strata)
# e.g., 17=High, 19=Low; 0=OtherBuild synthetic data
Use real subunit IDs from the DAU. The subunit lookup provides the
management_unit_id (GMU) for each subunit, which the
estimation pipeline requires.
# Look up subunits for the DAU
subunits <- spdgt.core::lkup_read_subunit(dau_id = dau_id)
# Pick 10 subunits, 2 observations each (one per stratum)
su <- subunits[1:10, ]
obs <- tibble::tibble(
species_id = species_id,
bio_year = 2024L,
analysis_unit_id = dau_id,
survey_type_id = survey_type_id,
management_unit_id = rep(su$management_unit_id, each = 2),
subunit_id = rep(su$id, each = 2),
stratum_id = rep(c(17L, 19L), 10),
is_selected = TRUE,
is_surveyed = TRUE,
total = as.integer(sample(1:30, 20, replace = TRUE)),
males = NA_integer_,
females = NA_integer_,
youngs = NA_integer_,
unclass = NA_integer_,
activity = as.integer(sample(1:4, 20, replace = TRUE)),
vegetation_type = as.integer(sample(1:2, 20, replace = TRUE)),
snow_percentage = as.integer(sample(0:80, 20, replace = TRUE)),
metadata = replicate(20, list(), simplify = FALSE)
)
# Fill in demographic breakdowns
obs$males <- as.integer(round(obs$total * 0.35))
obs$females <- as.integer(round(obs$total * 0.40))
obs$youngs <- as.integer(round(obs$total * 0.20))
obs$unclass <- obs$total - obs$males - obs$females - obs$youngsFit the model
results <- sight_fit_model_id(
spatial_focus = "DAU",
model_id = model_id,
data = obs
)
print(results)
# Returns a tibble with columns:
# species_id, bio_year, analysis_unit_id, spatial_focus,
# survey_type_id, model_id, Demographic, RawCount, Estimate,
# SightInflation, SampInflation, TotalVar, SE, LCL, UCL, CVExample 2: Ratio estimation (composition model)
Composition surveys produce demographic ratios (e.g., fawn:doe) without spatial extrapolation. The data is simpler – no covariates are needed.
Discover IDs
species_id <- lkup_species_id("Mule Deer")
# Look up a Composition survey type
survey_type_id <- lkup_survey_type_id(
"Composition",
species_id = species_id
)
dau_id <- lkup_dau_id(
"North Converse 755",
species_id = species_id
)
# Find models for this species + survey type
models <- sight_read_model(
species = "Mule Deer",
survey_type = "Composition"
)
model_id <- models$id[1]
# Confirm estimation method
model <- sight_read_model(id = model_id)
model$metadata[[1]]
# Expect method = "cochran" or "quasibinomial"Build synthetic data
# Re-use subunit lookup from the DAU
subunits <- spdgt.core::lkup_read_subunit(dau_id = dau_id)
su <- subunits[1:15, ]
obs <- tibble::tibble(
species_id = species_id,
bio_year = 2024L,
analysis_unit_id = dau_id,
survey_type_id = survey_type_id,
management_unit_id = su$management_unit_id,
subunit_id = su$id,
stratum_id = 0L,
is_selected = TRUE,
is_surveyed = TRUE,
total = as.integer(sample(10:50, 15, replace = TRUE)),
males = NA_integer_,
females = NA_integer_,
youngs = NA_integer_,
unclass = 0L,
metadata = replicate(15, list(), simplify = FALSE)
)
# Fill in demographic breakdowns
obs$males <- as.integer(round(obs$total * 0.30))
obs$females <- as.integer(round(obs$total * 0.45))
obs$youngs <- as.integer(round(obs$total * 0.20))
obs$unclass <- obs$total - obs$males - obs$females - obs$youngsFit the model
results <- sight_fit_model_id(
spatial_focus = "DAU",
model_id = model_id,
data = obs
)
print(results)
# Returns a tibble with ratio estimates:
# Demographic = "MFRatio", "YFRatio", etc.
# Estimate, TotalVar, SE, LCL, UCLTips
- Models are linked to survey types. Always filter by species + survey type when looking up models.
-
Covariate codings come from the betas table. Check
sight_read_betas_id(model_id, includes = "covar")to see the expected integer codes for activity and vegetation_type. -
stratum_id = 0orNAmaps to “Other” – a non-extrapolating stratum used for opportunistic observations. -
metadatacan belist(). It is only needed when entry-column-mapping transforms were applied to the original data. -
is_selected = NArows are treated as unselected (design-only units not in the sampling frame). -
To modify real data rather than building from
scratch, start with
sight_read_data_id()and edit the returned tibble. Columns that are allNA(e.g.,metadata) may be dropped during JSON serialization to the API, so replace them with a list column before sending:
data <- sight_read_data_id(
species_id = species_id,
survey_type_id = survey_type_id,
analysis_unit_id = dau_id,
bio_year = 2024
)
# Make your modifications
data$total[1] <- 25L
# Ensure metadata column survives JSON round-trip
data$metadata <- replicate(nrow(data), list(), simplify = FALSE)
# Pass modified data to the model
results <- sight_fit_model_id(
spatial_focus = "DAU",
model_id = model_id,
data = data
)