georest.usfs.vocab

Cached, searchable vocabularies for the FIADB-API.

FIADB-API’s /fullreport takes an estimate attribute, a row grouping, a column grouping, and an evaluation. Live counts, measured against the API:

Parameter

Count

What it selects

snum / sdenom

752

Estimate attribute (numerator/denominator)

rselected etc.

96

Grouping variable (row / column / page)

wc

1143

Evaluation (state + year + eval group)

That is a combinatorial space no one memorizes, and the published docs still say “This page is under construction”. Nothing in the official documentation mentions that the parameter endpoints accept outputFormat=JSON, but they do, and that is what makes discovery possible at all: the entire vocabulary is machine-readable, about 1.4 MB in total, and changes per release rather than per query.

So it is cached, and search runs locally: a bundled snapshot ships with the package, a refreshed copy lives in a user cache, and the cache is revalidated after about 30 days.

Failure is always backward, never forward. A vocabulary lookup falls from user cache, to bundled snapshot, to an empty result. It does not raise, and it does not block on the network. Discovery is what people do before they know what they want; making it fragile makes the whole package feel fragile.

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

FIA_CATALOGS

FIA parameter catalogs, by the query-parameter name they populate.

FIA_CATALOG_ALIASES

Aliases onto the three fetched catalogs.

CACHE_TTL_SECONDS

Refresh interval.

Functions

cache_dir()

Directory for refreshed catalogs.

describe_grouping(label)

Prose documentation for a grouping variable, codes included.

find_attributes([query, land_basis, ...])

Search the 752 FIA estimate attributes.

find_evaluations([state, most_recent, ...])

Search the 1,143 FIA evaluations.

find_groupings([query, limit])

Search the 96 FIA grouping variables.

get_attribute(snum)

Full record for one attribute number, or None.

get_evaluation(wc)

Full record for one evaluation group, or None.

grouping_labels()

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

load_catalog(name, *[, refresh])

Return one vocabulary, from memory, cache, bundle, or the network.

refresh_all(*[, quiet])

Force-refresh every catalog.

georest.usfs.vocab.FIA_CATALOGS = ('snum', 'rselected', 'wc')

FIA parameter catalogs, by the query-parameter name they populate. sdenom shares snum’s vocabulary and cselected/pselected share rselected’s, so only the distinct ones are fetched.

georest.usfs.vocab.FIA_CATALOG_ALIASES = {'cselected': 'rselected', 'pselected': 'rselected', 'sdenom': 'snum'}

Aliases onto the three fetched catalogs.

georest.usfs.vocab.CACHE_TTL_SECONDS = 2592000

Refresh interval. These change when FIA publishes a new evaluation cycle, an annual-ish cadence, so 30 days picks changes up well before anyone notices and keeps the network essentially off the hot path.

georest.usfs.vocab.cache_dir() → Path[source]

Directory for refreshed catalogs.

~/.georest/usfs, beside the ArcGIS sign-in that georest keeps in ~/.georest. Overridable with GEOREST_USFS_CACHE for tests and for locked-down machines where the home directory is not writable.

Example:

from georest.usfs import vocab

vocab.cache_dir()   # Path to ~/.georest/usfs in your home directory
georest.usfs.vocab.load_catalog(name: str, *, refresh: bool = False) → list[dict][source]

Return one vocabulary, from memory, cache, bundle, or the network.

Parameters:
  • name – A catalog or alias: any of snum, sdenom, rselected, cselected, pselected, wc.

  • refresh – Force a network fetch, ignoring the TTL. Still falls back to cached data if the fetch fails.

Returns:

List of records. Empty only when every source failed, which means discovery degrades rather than breaking.

Example:

from georest.usfs import vocab

rows = vocab.load_catalog("wc")          # every FIA evaluation, as dicts
len(rows), sorted(rows[0])[:4]
georest.usfs.vocab.refresh_all(*, quiet: bool = False) → dict[str, int][source]

Force-refresh every catalog. Returns {name: record_count}.

The escape hatch for “a new evaluation just dropped and I do not want to wait out the TTL”. Normal use should never need it.

Example:

from georest.usfs import vocab

vocab.refresh_all()   # prints each catalog's record count; returns {name: count}
georest.usfs.vocab.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.vocab.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.vocab.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.vocab.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.vocab.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.vocab.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.vocab.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'