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
Flag a cell whose standard error exceeds this percentage. |
|
Flag a cell resting on fewer than this many plots. |
|
for Nevada's current evaluation, 10.52 million acres under FIADEF and 7.69 million under RPADEF (checked 2026-10-27). |
Functions
|
Run an FIA estimate and return it tidy, with its sampling error. |
|
Drop cells flagged unreliable. |
|
Check an attribute is answerable by an evaluation. |
Exceptions
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.DataFramewith the columns that matter for choosing an attribute: number, description, units, and the evaluation type it requires. The full record is available viaget_attribute().
Note
FIA’s own catalog contains duplicate descriptions: 7 of the 752 appear more than once.
snum209 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/pselectedaccept, and they are passed as display strings, so the exactlabelin 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
rselectedand 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
fullreportcall.- 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 returnedforest_definitioncolumn 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 thedb_columnvalues fromfind_groupings()(P.,C.,PG.) are NOT accepted here: EVALIDator answersp.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 onplot..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, plusattribute,evaluationandforest_definitionfor provenance. Warnings the API attached to the estimate are indf.attrs["warnings"], and logged.- Return type:
pandas.DataFramewith 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:
ValueErrorA 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·SErelies on.