georest.usfs.align¶
Putting LCMS and FIA side by side, without pretending they agree.
The two answer complementary halves of one question over overlapping geography, and almost nobody joins them because the APIs look nothing alike. That is the opportunity. The hazard is that joining them invites a comparison that is easy to make and easy to get wrong.
Aspect |
LCMS |
FIA |
|---|---|---|
Nature |
Wall-to-wall classified map |
Probability sample |
Resolution |
30 m, annual, 1985-2025 |
Plots, multi-year panels |
Answers |
What changed, and where |
What is there, +/- error |
Uncertainty |
Map accuracy |
Design-based std. error |
Map-derived area is not a design-based area estimate. Comparing them conflates map accuracy with sampling error, and the two can differ substantially without either being wrong - different definitions of “forest”, different minimum mapping units, different reference dates.
So nothing here returns a blended number. Every row carries the
source and estimator that produced it, and the comparison
helpers report a difference alongside the caveat rather than instead
of it. The goal is to make the comparison easy to look at and hard to
misread.
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
LCMS land-cover classes that carry tree cover. |
|
Why LCMS and FIA can legitimately disagree. |
|
FIA attribute 2 - "Area of forest land, in acres". |
Functions
|
Put an LCMS treed area and an FIA forest-land estimate side by side. |
|
FIA forest-land area with its sampling error. |
|
LCMS area in tree-bearing land cover classes, by year. |
|
One readable paragraph from |
- georest.usfs.align.TREE_CLASSES = ('Trees', 'Tall Shrubs & Trees Mix (AK Only)', 'Shrubs & Trees Mix', 'Grass/Forb/Herb & Trees Mix', 'Barren & Trees Mix')¶
LCMS land-cover classes that carry tree cover. Used to build a “treed area” figure that is comparable in spirit to FIA forest land - not equal to it. FIA’s definition is about land use and stocking potential, not present canopy, so a recently harvested stand stays forest land in FIA while LCMS may map it as grass or barren in the same year. That divergence is real signal, and it is exactly what a naive join would hide.
The
(AK Only)suffix is part of the real class name, not a comment. Writing it without the suffix looks correct, matches nothing, and silently drops the class - invisible in CONUS where it never occurs, and an understatement of tree area everywhere in Alaska. That is whylcms_tree_area()validates these names against the API’s class list rather than trusting this tuple.
- georest.usfs.align.COMPARISON_CAVEATS = ('LCMS area is map-derived; FIA area is a design-based estimate. The difference mixes map accuracy with sampling error and is not an error term for either.', "FIA 'forest land' is a land-use definition based on stocking and potential; LCMS land cover describes present canopy. A recently harvested stand stays forest land in FIA while LCMS may map it as grass or barren the same year.", 'Reference periods differ: an FIA evaluation spans several years of panels, while an LCMS year is a single annual map.', 'Minimum mapping unit and edge handling differ, which matters most in fragmented landscapes.')¶
Why LCMS and FIA can legitimately disagree. Module-level on purpose: these are static facts about the two datasets, not properties of any one comparison, so they must be readable even when the FIA half of a comparison could not be fetched. Gating them behind a successful call meant the caveats vanished exactly when a reader had one number and might quote it alone.
- georest.usfs.align.FOREST_AREA_SNUM = 2¶
FIA attribute 2 - “Area of forest land, in acres”.
- georest.usfs.align.lcms_tree_area(state: str = '', county: str = '', *, region: str = '', forest: str = '', district: str = '', year: int | None = None, tree_classes: tuple | None = None, release: str = '') Any[source]¶
LCMS area in tree-bearing land cover classes, by year.
- Parameters:
tree_classes – Override which classes count as treed. The default includes the mixed classes, which matters: excluding them understates treed area in exactly the transitional stands where LCMS and FIA are most likely to disagree.
- Returns:
pandas.DataFramewithyear,acres,classes_used,source,estimator.
Example:
from georest.usfs import align # Acres in tree-bearing LCMS land cover classes, per year align.lcms_tree_area(state="Oregon", county="Crook")
- georest.usfs.align.fia_forest_area(wc: int, *, rselected: str = '', snum: int = 2, **kwargs) Any[source]¶
FIA forest-land area with its sampling error.
Thin wrapper over
estimate()that stamps the estimator label, so a frame from here and a frame fromlcms_tree_area()can be concatenated without losing track of which is which.Example:
from georest.usfs import align, fia oregon = fia.find_evaluations("Oregon")["wc"].iloc[0] align.fia_forest_area(oregon) # forest land with se_pct and plots, labelled as FIA
- georest.usfs.align.compare_area(*, wc: int, state: str = '', county: str = '', year: int | None = None, tree_classes: tuple | None = None, release: str = '') dict[str, Any][source]¶
Put an LCMS treed area and an FIA forest-land estimate side by side.
Returns a dict rather than a single frame, because the two halves are not rows of one table - they are two different estimators of two related-but-distinct quantities, and stacking them would imply a comparability that does not exist.
Keys:
lcms- per-year treed area frame.fia- forest-land estimate withse_pctandplots.comparison- a small dict with both figures, their absolute and percentage difference, andcaveats, a list of the reasons they can legitimately disagree.
The difference is offered as an observation, never as an error term. A 15% gap between these does not mean either is 15% wrong.
Example:
from georest.usfs import align, fia oregon = fia.find_evaluations("Oregon")["wc"].iloc[0] result = align.compare_area(wc=oregon, state="Oregon", county="Crook", year=2024) result["comparison"] # both figures, their difference, and the caveats
- georest.usfs.align.summarize_comparison(result: dict[str, Any]) str[source]¶
One readable paragraph from
compare_area(), caveats included.Written to be pasted into a report. The caveat is part of the sentence rather than a footnote, because a number this easy to quote is a number that travels without its footnotes.
Example:
from georest.usfs import align, fia oregon = fia.find_evaluations("Oregon")["wc"].iloc[0] result = align.compare_area(wc=oregon, state="Oregon", county="Crook", year=2024) print(align.summarize_comparison(result)) # one paragraph, caveats included