Skip to content

Remove trees with road and water features

You are viewing in-progress documentation for v2 (Beta). Switch to the stable version for the current production release.

A tree inventory shouldn’t put trees in a lake or on a road. This guide removes those trees by testing each one against a road or water Feature resource on the domain — the inventory counterpart to masking a fuel grid.

Two recipes:

  1. Remove every tree within 5 m of water (recipe C).
  2. Remove only large trees within 5 m of a road — a spatial condition combined with a DBH threshold (recipe D).

Trees are points, so a spatial condition is a point-in-polygon test. There’s no target field (nothing to choose for a point), and because a point almost never lands exactly on a feature’s edge, buffer_m is how you give the feature width. For the concepts, see About modifications.

The modifications attach to the inventory create call, so the trees are filtered as the inventory is generated — there’s no separate edit step.

  1. An API key: my-api-key.

  2. A domain in a projected CRS: your-domain-id. See Create a domain.

  3. A completed road feature and water feature in that domain. See Create road and water features from OpenStreetMap — create both, poll them to completed, and record your-road-feature-id and your-water-feature-id.

  4. A completed PIM source grid. A TreeMap PIM inventory is generated from a pim grid, so create one first:

    Create TreeMap PIM grid
    curl -X 'POST' \
    'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/grids/pim/treemap' \
    -H 'accept: application/json' \
    -H 'api-key: my-api-key' \
    -H 'Content-Type: application/json' \
    -d '{
    "name": "TreeMap PIM grid"
    }'

    Poll it to completed (it’s small — a TreeMap grid is coarse), then record your-pim-grid-id:

    {
    "id": "your-pim-grid-id",
    "domain_id": "your-domain-id",
    "name": "TreeMap PIM grid",
    "description": "",
    "status": "completed",
    "progress": {
    "percent": 100,
    "message": "Complete"
    },
    "created_on": "2026-06-02T19:02:18.555673Z",
    "modified_on": "2026-06-02T19:02:21.344594Z",
    "source": {
    "bands": ["tm_id"],
    "product": "treemap",
    "name": "pim",
    "alignment": {
    "target": "domain",
    "resolution": null,
    "method": null
    },
    "version": "2022",
    "extent_buffer_cells": 0,
    "description": "TreeMap plot imputation raster (FIA plot IDs at 30m)"
    },
    "modifications": [],
    "bands": [
    {
    "key": "tm_id",
    "type": "categorical",
    "unit": null,
    "index": 0,
    "nodata": 4294967295
    }
    ],
    "georeference": {
    "crs": "EPSG:32611",
    "transform": [
    29.703174954781062, 0.0, 717141.6556112946, 0.0, -29.703174954785382,
    5328277.037140956
    ],
    "shape": [59, 53]
    },
    "error": null,
    "chunks": {
    "shape": [512, 512],
    "count": 1,
    "count_by_axis": {
    "y": 1,
    "x": 1
    }
    },
    "tags": []
    }

Recipe C — remove every tree within 5 m of water

Section titled “Recipe C — remove every tree within 5 m of water”

Create the inventory with one modification rule: a within test against the water feature, grown by a 5 m buffer_m, and a remove action. remove must be the only action in its rule — you can’t both drop a tree and edit it.

Create inventory — trees near water removed
curl -X 'POST' \
'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/inventories/tree/pim' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Trees with 5 m water buffer removed",
"source_pim_grid_id": "your-pim-grid-id",
"seed": 42,
"modifications": [
{
"conditions": [
{"source": "feature", "operator": "within", "feature_id": "your-water-feature-id", "buffer_m": 5}
],
"actions": [
{"modifier": "remove"}
]
}
]
}'

The 201 echoes your rule and mints an inventory id — record it: your-inventory-id. Status starts pending; the removal runs server-side while the inventory is built.

GET inventory status
curl -X 'GET' \
'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/inventories/your-inventory-id' \
-H 'accept: application/json' \
-H 'api-key: my-api-key'
{
"id": "your-inventory-id",
"domain_id": "your-domain-id",
"type": "tree",
"name": "Trees with 5 m water buffer removed",
"description": "",
"status": "completed",
"progress": {
"percent": 100,
"message": "Complete"
},
"created_on": "2026-06-02T19:03:44.532009Z",
"modified_on": "2026-06-02T19:03:54.274920Z",
"source": {
"seed": 42,
"name": "pim",
"source_pim_grid_id": "your-pim-grid-id",
"point_process": "inhomogeneous_poisson"
},
"modifications": [
{
"conditions": [
{
"source": "feature",
"operator": "within",
"feature_id": "your-water-feature-id",
"buffer_m": 5.0
}
],
"actions": [
{
"modifier": "remove"
}
]
}
],
"columns": [
{
"key": "x",
"type": "continuous",
"unit": "m"
},
{
"key": "y",
"type": "continuous",
"unit": "m"
},
{
"key": "fia_species_code",
"type": "categorical",
"unit": null
},
{
"key": "fia_status_code",
"type": "categorical",
"unit": null
},
{
"key": "dbh",
"type": "continuous",
"unit": "cm"
},
{
"key": "height",
"type": "continuous",
"unit": "m"
},
{
"key": "crown_ratio",
"type": "continuous",
"unit": null
}
],
"georeference": {
"crs": "EPSG:32611",
"bounds": [
717141.6556112946, 5326524.549818624, 718694.8955395881, 5328248.228078655
]
},
"error": null,
"tags": []
}

On this domain the rule removes 763 trees (82,961 → 82,198) — the ones inside the water bodies plus the 5 m shoreline tolerance. The shaded ring is that removal zone:

Domain 5 m buffer Water
Water bodies (blue) and the 5 m buffer (light blue) within the domain. Every tree whose point falls in the light-blue zone is removed.

Recipe D — remove only large trees within 5 m of a road

Section titled “Recipe D — remove only large trees within 5 m of a road”

Add a second condition to the same rule. Conditions are ANDed, so a tree is removed only if it’s both inside the buffered road and above a DBH threshold. Here: trees over 10 inches DBH within 5 m of a road. The unit: "in" converts the threshold to the native cm before comparing, so you don’t have to do the arithmetic.

Create inventory — large trees near roads removed
curl -X 'POST' \
'https://api-v2-prod-nyvjyh5ywa-uw.a.run.app/domains/your-domain-id/inventories/tree/pim' \
-H 'accept: application/json' \
-H 'api-key: my-api-key' \
-H 'Content-Type: application/json' \
-d '{
"name": "Large trees within 5 m of roads removed",
"source_pim_grid_id": "your-pim-grid-id",
"seed": 42,
"modifications": [
{
"conditions": [
{"source": "feature", "operator": "within", "feature_id": "your-road-feature-id", "buffer_m": 5},
{"attribute": "dbh", "operator": "gt", "value": 10, "unit": "in"}
],
"actions": [
{"modifier": "remove"}
]
}
]
}'

This removes 196 trees — only the large ones in the road corridor. Smaller trees inside the same buffer survive, because the DBH condition narrows the spatial one. Drop the DBH condition and the rule would remove every tree in the buffer instead.

Domain 5 m buffer Roads
Roads (red) and the 5 m buffer (orange). Trees in the orange zone are removed only if they also clear the DBH threshold.

Both operators work on point geometries, and for a tree-against-polygon test they behave the same: a point is “within” a polygon exactly when it “intersects” it. Use within for readability (“trees within the water”). outside is the inverse — keep it for “everything except near the feature.”

  • remove combined with another action. remove must be the sole action in its rule — “remove this tree and also set its height” is incoherent, and the API rejects it. To edit surviving trees and remove others, use two separate rules.

  • Expecting buffer_m: 0 to catch trees near water. It won’t — see the caution above. Give the feature width with a non-zero buffer.

  • Wrong DBH units. DBH’s native unit is centimeters. A bare "value": 10 means 10 cm, not 10 inches. Add "unit": "in" (as in recipe D) when you mean inches — the server converts before comparing.

  • Same-domain rule. The road/water feature must live in the same domain as the inventory. A feature from another domain is rejected.