georest.usfs.fia

FIADB-API client - Forest Inventory and Analysis estimates.

Wraps EVALIDator, the USFS tool behind fiadb-api/fullreport. EVALIDator is the name people know this service by, so it is said here in prose: an agent searching the codebase for “EVALIDator” found nothing but a test, because the word lived only in comments.

FIA is a probability sample of forest plots, not a census. Every estimate it produces is a design-based estimate with a sampling error, and this client is built around refusing to let you forget that.

A real query illustrates why. Forest area by county and forest type group for Alabama returns, among 4,241 plots:

Forest type group

Acres

SE (%)

Plots

Total

22,963,960

0.51

4241

Longleaf / slash pine group

1,184,334

6.07

258

White / red / jack pine group

15,748

54.92

4

That last row is a number with a 54.9% standard error resting on four plots. Rendered as a bare value in a chart it reads as fact. So estimate() returns se_pct and plots on every row, and flags the ones too thin to report.

Why plot count as well as standard error, when SE already grows as the sample shrinks: there are three regimes where SE cannot police itself. At n = 0 it is zero or undefined - reading as maximum precision when it means no information, which is the dangerous inversion. At n = 1 no variance estimate exists at all. And at small n the SE is itself estimated from that same tiny sample, so a small value can be luck rather than precision. There is a fourth, quieter problem: an SE is normally consumed as estimate ± 1.96·SE, which assumes approximate normality - at small n that interval undercovers, in the direction of overconfidence.

See Bechtold & Patterson, The Enhanced Forest Inventory and Analysis Program (GTR-SRS-80), for the estimation design itself.

Copyright 2026 Ryan Rock and Ian Housman

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

Module Attributes

DEFAULT_MAX_SE_PCT

Flag a cell whose standard error exceeds this percentage.

DEFAULT_MIN_PLOTS

Flag a cell resting on fewer than this many plots.

FOREST_DEFINITIONS

for Nevada's current evaluation, 10.52 million acres under FIADEF and 7.69 million under RPADEF (checked 2026-10-27).

Functions

estimate(wc, snum, *[, rselected, ...])

Run an FIA estimate and return it tidy, with its sampling error.

reliable(df)

Drop cells flagged unreliable.

validate(wc, snum)

Check an attribute is answerable by an evaluation.

Exceptions

FIAValidationError

A request that would fail upstream, caught locally first.

georest.usfs.fia.find_attributes(query: str = '', *, land_basis: str = '', eval_typ: str = '', limit: int | None = None) → Any[source]

Search the 752 FIA estimate attributes.

Parameters:
  • query – Free text matched against description and group, e.g. "carbon", "net growth volume", "mortality".

  • land_basis – Restrict to "Forest land" or "Timberland".

  • eval_typ – Restrict to an evaluation type: EXPCURR, EXPVOL, EXPGROW, EXPMORT, EXPREMV, EXPCHNG, EXPDWM.

  • limit – Return at most this many rows. By default every match is returned, best first.

Returns:

A pandas.DataFrame with the columns that matter for choosing an attribute: number, description, units, and the evaluation type it requires. The full record is available via get_attribute().

Note

FIA’s own catalog contains duplicate descriptions: 7 of the 752 appear more than once. snum 209 and 956, for instance, are identical across description, estimate group, evaluation type, estimation basis and tree portion. Both are returned rather than silently de-duplicated, because they are distinct attribute numbers upstream and collapsing them would hide a real property of the catalog. Where descriptions match on every field, either number should produce the same estimate.

Example:

from georest.usfs import fia

# Every carbon attribute measured on forest land, best match first
fia.find_attributes("carbon", land_basis="Forest land")

# Attributes that need growth accounting (growth, removals, mortality)
fia.find_attributes("mortality", eval_typ="EXPMORT")
georest.usfs.fia.get_attribute(snum: int) → dict | None[source]

Full record for one attribute number, or None.

Example:

from georest.usfs import fia

fia.get_attribute(2)["ATTRIBUTE_DESCR"]   # 'Area of forest land, in acres'
georest.usfs.fia.find_evaluations(state: str = '', *, most_recent: bool = True, growth_only: bool = False, limit: int | None = None) → Any[source]

Search the 1,143 FIA evaluations.

Parameters:
  • state – State name, matched case-insensitively on a prefix.

  • most_recent – Keep only each state’s current evaluation. Almost always what you want; set False to see the back catalog.

  • growth_only – Keep only evaluations with growth accounting (GROWTH_ACCT == 'Y'), which is a prerequisite for every growth, removals, and mortality attribute.

  • limit – Return at most this many rows. By default every match is returned.

Example:

from georest.usfs import fia

fia.find_evaluations("Oregon")                     # the current inventory
fia.find_evaluations("Oregon", most_recent=False)  # and every earlier one
fia.find_evaluations("Oregon", growth_only=True)   # usable for growth and mortality
georest.usfs.fia.get_evaluation(wc: int) → dict | None[source]

Full record for one evaluation group, or None.

Example:

from georest.usfs import fia

fia.get_evaluation(412024)["REPORT_YEAR_NM"]   # '2015;2016;...;2024'
georest.usfs.fia.find_groupings(query: str = '', *, limit: int | None = None) → Any[source]

Search the 96 FIA grouping variables.

These are what rselected / cselected / pselected accept, and they are passed as display strings, so the exact label in this result is what the query needs, character for character.

Parameters:
  • query – Free text matched against the label and database column.

  • limit – Return at most this many rows. By default every match is returned, best first.

Example:

from georest.usfs import fia

fia.find_groupings("owner")   # labels to pass as rselected= / cselected=
georest.usfs.fia.describe_grouping(label: str) → str[source]

Prose documentation for a grouping variable, codes included.

FIA ships this as PRC_METADATA, an HTML fragment that usually enumerates what each code value means. It is the difference between a column of integers and a column you can interpret, so it is worth surfacing rather than leaving buried in the catalog.

Example:

from georest.usfs import fia

# What each code of a grouping means, as plain text
fia.describe_grouping("Ownership group - Major")
georest.usfs.fia.grouping_labels() → list[str][source]

Every grouping label, exactly as rselected and friends need it.

Example:

from georest.usfs import vocab

"Forest type group" in vocab.grouping_labels()   # True
georest.usfs.fia.estimate(wc: int | Sequence[int], snum: int, *, rselected: str = '', cselected: str = '', pselected: str = '', sdenom: int | None = None, forest_definition: str = 'FIADEF', str_filter: str = '', max_se_pct: float = 30.0, min_plots: int = 30, validate_first: bool = True) → Any[source]

Run an FIA estimate and return it tidy, with its sampling error.

This is the EVALIDator fullreport call.

Parameters:
  • wc – Evaluation group, see find_evaluations(). Pass several ([102025, 242025]) to estimate across them in one request. That is the only way to get a correct combined standard error: estimating each separately gets a summed total right, but not its error.

  • snum – Estimate attribute - see find_attributes().

  • rselected – Row grouping, as the exact display string from find_groupings().

  • cselected – Column grouping. Optional.

  • pselected – Page grouping. Optional.

  • sdenom – Denominator attribute, to produce a ratio estimate.

  • forest_definition – "FIADEF" (the default) or "RPADEF". The two define forest land differently and give different areas, so it is always sent explicitly. The returned forest_definition column carries the definition the server reports having applied, so a saved frame records it.

  • str_filter –

    SQL-style filter passed through as strFilter. Qualify columns with the FULL table name - plot.unitcd, cond.owncd, tree.spcd. The short aliases that appear in FIA documentation and in the db_column values from find_groupings() (P., C., PG.) are NOT accepted here: EVALIDator answers p.unitcd in (0, 1, 2) with HTTP 200 carrying an “Internal Server Error - SQL Error” page, which says nothing about the alias being the problem. Two separate agent sessions burned several turns guessing before landing on plot..

    Example - western Oregon survey units only:

    estimate(wc=412022, snum=98, rselected="Unit code",
             str_filter="plot.unitcd in (0, 1, 2)")
    

  • max_se_pct – Flag cells whose standard error exceeds this.

  • min_plots – Flag cells resting on fewer plots than this.

  • validate_first – Check attribute/evaluation compatibility locally before sending. Turn off only to probe the API directly.

Returns:

row, column, estimate, se_pct, plots, units, unreliable, unreliable_reason, plus attribute, evaluation and forest_definition for provenance. Warnings the API attached to the estimate are in df.attrs["warnings"], and logged.

Return type:

pandas.DataFrame with one row per cell

Raises:
  • FIAValidationError – The request would fail upstream.

  • UpstreamError / UpstreamUnavailable – The API refused or could not be reached.

Example:

from georest.usfs import fia

oregon = fia.find_evaluations("Oregon")["wc"].iloc[0]

# Forest land (attribute 2) by county, each cell with its sampling error
df = fia.estimate(oregon, 2, rselected="County code and name")
df[["row", "estimate", "se_pct", "plots", "unreliable"]]

# Oregon and Washington as one estimate, with a correct combined error
washington = fia.find_evaluations("Washington")["wc"].iloc[0]
both = fia.estimate([oregon, washington], 2)
both[both["row"] == "Total"]
both.attrs["warnings"]   # anything FIADB-API flagged about the estimate
georest.usfs.fia.validate(wc: int | Sequence[int], snum: int) → None[source]

Check an attribute is answerable by an evaluation. Raises if not.

Pre-flight for the EVALIDator request, so a bad pairing fails here with a named reason instead of arriving as EVALIDator’s own “Key Error / Received an Error” HTML page.

Attributes declare the evaluation type they need (EXPCURR, EXPVOL, EXPGROW, EXPMORT, EXPREMV, EXPCHNG, EXPDWM); evaluations advertise whether they support growth accounting. The pairing is knowable before the request leaves.

Example:

from georest.usfs import fia

# Wyoming's current inventory has no growth accounting, so a
# mortality attribute is refused here, with the reason, before any
# request is sent.
wyoming = fia.find_evaluations("Wyoming")["wc"].iloc[0]
mortality = fia.find_attributes("mortality", eval_typ="EXPMORT")["snum"].iloc[0]
try:
    fia.validate(wyoming, mortality)
except fia.FIAValidationError as err:
    print(err)
georest.usfs.fia.reliable(df) → Any[source]

Drop cells flagged unreliable.

Separate from estimate() on purpose. The data layer returns everything with a reason attached; discarding is the caller’s decision, and a silent drop at fetch time would hide how much of a cross-tabulation is too thin to use.

Example:

from georest.usfs import fia

oregon = fia.find_evaluations("Oregon")["wc"].iloc[0]
df = fia.estimate(oregon, 2, rselected="Forest type group")
fia.reliable(df)   # the same table without the cells flagged too uncertain
exception georest.usfs.fia.FIAValidationError[source]

Bases: ValueError

A request that would fail upstream, caught locally first.

Every check here is cheap and offline. Turning an opaque server error into a specific local one matters most for agents, where a rejected call costs a whole turn.

georest.usfs.fia.FOREST_DEFINITIONS = ('FIADEF', 'RPADEF')

for Nevada’s current evaluation, 10.52 million acres under FIADEF and 7.69 million under RPADEF (checked 2026-10-27). The definition is always sent explicitly, so two people pulling “the same” number agree.

Type:

Forest land definitions. FIA and RPA produce different areas

georest.usfs.fia.DEFAULT_MAX_SE_PCT = 30.0

Flag a cell whose standard error exceeds this percentage.

georest.usfs.fia.DEFAULT_MIN_PLOTS = 30

Flag a cell resting on fewer than this many plots. 30 is the conventional floor for the normal approximation that turns an SE into a confidence interval - which is exactly the assumption ± 1.96·SE relies on.