Landform Classification

Topographic Analysis · TPI Tools · geoprocessing tool · by Jeff Jenness
Works at every ArcGIS Pro license level

Summary

Classifies a DEM into landform categories — canyons, midslope drainages, upland drainages, U-shaped valleys, plains, open slopes, upper slopes and mesas, local and midslope ridges, and mountain tops — from a small- and a large-neighborhood Topographic Position Index (TPI; Weiss 2001, after Guisan et al. 1999) plus slope, using a saved classification system such as the ten-class system adapted from Weiss (2001). The two TPIs and the slope are computed internally from the DEM, with no Spatial Analyst extension, or you may supply rasters you already have.

The ten categories listed above are Weiss's, not the tool's. The tool applies whatever classification system it is given, and the Classification System Builder lets you define your own: as many or as few classes as your question needs, with thresholds, names and colors set for your own landscape and purpose.

The combination of two scales is what distinguishes a landform from a slope position. A cell that is high relative to its immediate surroundings but low relative to the broad landscape is a local ridge or hill inside a larger valley; a cell that is low at the small scale and high at the large scale is an upland drainage. As with all TPI analysis (and most neighborhood analysis in general), picking the right neighborhood size is important, and often difficult to estimate; here there are two to pick, the small one to capture the local features you care about and the large one the broad context. Each may be a circle or an annulus, with its radius in cells or ground units, and each TPI may be raw, standardized or in percentile units, as the classification system expects.

Learn more About TPI explains the Topographic Position Index, why its scale is part of the answer, and how the six TPI tools fit together. The Slope Position Classification tool is the single-scale companion of this one, and the Topographic Position Index tool computes the TPI rasters this tool can classify.

Two scales make a landform

The Topographic Position Index is a cell's elevation minus the mean elevation of a neighborhood around it: positive on ground that stands above its surroundings, negative on ground that sits below them, and near zero on flats and even slopes. One TPI, at one neighborhood size, sorts the landscape into slope positions. Two TPIs, at a small and a large neighborhood, sort it into landforms, because the pair says both where a cell sits locally and where its local setting sits in the wider landscape. The profile below, from the manual of the ArcView 3.x TPI extension (Jenness 2006), shows five landforms read from the two scales.

A terrain cross-section labeled Landform Classification using Large and Small Neighborhood TPI: an upland drainage (small-neighborhood TPI very low, large very high), a hill in a valley (small very high, large very low), an open slope (both mid-range, steep), a flat hilltop (small mid-range, large high) and a deeply incised stream (both very low), each marked with a short and a long neighborhood bracket
Five landforms on a profile. Each point carries two brackets, the small and the large neighborhood, and the pair of TPI values names the landform: a hill in a valley is high at the small scale and low at the large one; an upland drainage is the reverse. From the TPI extension manual (Jenness 2006).

Viewed in graph space, with the large-neighborhood TPI on the horizontal axis and the small-neighborhood TPI on the vertical, the combinations fall into place. Both negative is a deeply incised canyon; both positive is a sharp ridge or high peak; a positive small TPI on a negative large one is a small hill or ridge inside a larger valley; a negative small TPI on a positive large one is an upland drainage or a depression on high ground. Along the axes, where one TPI is near zero, lie the U-shaped valleys, the mesa tops, and the midslope drainages and ridges.

A diagram with negative-to-positive large-neighborhood TPI on the horizontal axis and small-neighborhood TPI on the vertical axis; the eight directions are labeled U-shaped canyons and valley bottoms (left), tops of mesas or gentle-sloped hills (right), small hills or ridges either midslope or in plains (up), midslope drainages or shallow valleys (down), sharp ridges and high peaks (upper right), deeply incised canyons or valley bottoms (lower left), midslope ridges or small hills in larger valleys (upper left) and upland drainages or depressions (lower right)
The plane of the two TPI values, and the landform each direction names. From the TPI extension manual (Jenness 2006).

Weiss (2001) turned this plane into ten classes by cutting each TPI at ±1 standard deviation and splitting the central square, where both TPIs are near zero, by slope: gentle ground there is a plain, steep ground an open slope. The bundled Weiss 10-Class Landform system is adapted from that scheme, with the classes and thresholds the table gives. Its TPI thresholds are in standard deviations of the elevations within each cell's own neighborhood rather than in Weiss's whole-raster standard deviations, and its slope threshold is 5°. Where a cell satisfies more than one class, the lowest class value wins.

ValueClassSmall-neighborhood TPILarge-neighborhood TPISlope
1Canyons, Deeply Incised Streams≤ −1≤ −1
2Midslope Drainages, Shallow Valleys≤ −1−1 < TPI < 1
3Upland Drainages, Headwaters≤ −1≥ 1
4U-shaped Valleys−1 < TPI < 1≤ −1
5Plains−1 < TPI < 1−1 < TPI < 1≤ 5°
6Open Slopes−1 < TPI < 1−1 < TPI < 1> 5°
7Upper Slopes, Mesas−1 < TPI < 1≥ 1
8Local Ridges, Hills in Valleys≥ 1≤ −1
9Midslope Ridges, Small Hills in Plains≥ 1−1 < TPI < 1
10Mountain Tops, High Ridges≥ 1≥ 1
A standardized 500-meter TPI map and a standardized 2000-meter TPI map of a canyon system, joined with a slope map to produce a landform categories map, with a ten-class legend giving each class's small-neighborhood and large-neighborhood TPI rules and, for plains and open slopes, the 5-degree slope split
Two standardized TPI rasters, 500 m and 2,000 m, plus slope, combined into the ten landform categories, slightly modified from Weiss (2001). From the TPI extension manual (Jenness 2006).

Weiss standardized the TPI at each scale before combining them, and gave the reason: because elevation is spatially autocorrelated, the range of TPI values grows with the size of the neighborhood, so a threshold in elevation units that suits the small scale is too small for the large one. Standardizing both to a mean of zero and a standard deviation of one lets one set of thresholds serve any pair of scales. He added the caution that this should only be done when the mean of each raw TPI is reasonably close to zero. The bundled system uses the neighborhood form of that standardization, each cell's TPI divided by the standard deviation of elevation in its own neighborhood (the “dev” of Wilson and Gallant 2000, equation 3.30), which is the form the Topographic Position Index tool calls standardized at neighborhood scale. Raw thresholds work too, and may suit an ecological question better, because a raw threshold is absolute relief; but then the small and large thresholds have to be set separately, and the Classification System Builder is where that is done.

An applied example

Tağıl and Jenness (2008) classified the landforms of the Yazoren Polje watershed in the Marmara region of Turkey, a basin of about 44 km² with a karstic depression at its center, from a 20 m DEM interpolated from the 10 m contours of 1:25,000 topographic maps. They computed TPI at six neighborhood radii, from 50 to 450 m, and classified slope position from each; the 100 m neighborhood did the best job of extracting the terraces and small karstic depressions of interest, because those features were too small for the larger neighborhoods, while the 50 m neighborhood picked out only their edges. For landforms they combined the 50 m and 450 m TPIs with slope using Weiss's ten classes, with thresholds of ±1 standard deviation and a 6° slope split. More than half of the watershed came out as open slopes, and nearly 93% of the alluvial surfaces fell into U-shaped valleys, plains or open slopes. The classification found the terraces along the gorge as local and midslope ridges and three erosional surfaces as upper slopes and mesas, and it showed the polje itself as a plain that gives way abruptly to open slopes along the fault lines that bound it. It also showed a limit of the method: several closed karst depressions came out as deeply incised streams and U-shaped valleys, with the ground around them as open slopes, because at these scales a closed depression and a valley look the same to the index, and narrow creeks crossing wide flats without a broader valley were not identified at all.

Choosing the two neighborhoods

The small neighborhood sets the local scale, and the large one the context. Make the large radius clearly larger than the small: the two must capture different landform scales, or the classification collapses to a slope position. Rasters written by the TPI tools carry their neighborhood radius in their metadata, and this tool compares the two when it can, warning if the small TPI's radius is not smaller than the large TPI's, since swapped or duplicated inputs would otherwise produce a wrong classification without any sign of it. When calculating on the fly it compares the two radii you type. Radii in cells and radii in ground units cannot be compared, and rasters made by other software cannot be checked.

The two scales choose their TPI type independently. The system's units set the defaults, one for each scale, and both may be overridden; a classification can combine, say, a raw small-neighborhood TPI with a percentile large-neighborhood TPI, if that is what its thresholds were written for. If a type does not match the system's units for that scale, the tool warns, names the scale in the warning, writes it into the output's metadata, and still runs. The same holds for slope units: the system declares whether its slope threshold is in degrees or percent, the dialog defaults to that, and a mismatch warns. On a geographic (latitude/longitude) DEM a ground-unit radius is sized per row on the spheroid, rounded east-west to a whole number of cells for each band of rows, so the neighborhood stays a circle on the ground to within about half a cell at any latitude.

The two neighborhoods can be tried one at a time with the TPI Neighborhood Sampler before a full run: pin a feature that should read as local relief and find the small radius that brings it out, then pin one that should read as regional relief and find the large one. The sampler works in the same raw and neighborhood standard deviation scales the system's criteria use.

A tour of the dialog

The dialog opens with the TPI and slope source choice. With Calculate TPI and Slope on-the-fly from DEM selected, the first group holds the DEM, the small neighborhood and its TPI type, the large neighborhood and its TPI type, the elevation units, the slope method and units, and three optional outputs for the generated small TPI, large TPI and slope rasters, which are stamped with their type, radius and units so a later run can reuse them. With Use Existing TPI and Slope Rasters selected, that group drops out of the dialog and the second group takes the two TPI rasters and the slope raster, each with an optional Declare dropdown that fills itself in from the raster's metadata when our tools wrote it. The classification system and the output follow in their own groups.

The Topographic Analysis Tools gallery open on the ribbon, with the Landform Classification button, in the TPI Tools row, outlined in blue
Where to find it: Landform Classification is in the TPI Tools row of the Topographic Analysis Tools gallery, in the Topographic Analysis group of the Wildlife and Forestry tab.

A Grand Canyon example from existing rasters

The example continues the Walhalla Plateau runs of the Topographic Position Index and Slope Position Classification pages. The two TPIs and the slope could have been generated on the fly from the DEM, but they already existed from that earlier work, so the run uses them as they are. The small-neighborhood TPI is the 500 m raster from the TPI page; the large-neighborhood TPI was computed the same way with a 2 km circular neighborhood.

Two raw TPI maps of the Walhalla Plateau over a hillshade in a blue-white-red stretch: on the left the 500 m neighborhood, from -350 to 447, with fine detail along every side canyon and spur; on the right the 2 km neighborhood, from -609 to 749, with the whole canyon system as broad blue bands and the plateau and its promontories as broad red; a 10 kilometer scale bar
The two scales, both raw TPI in meters. At 500 m (left, −350 to +447) every side canyon and spur shows; at 2 km (right, −609 to +749) the canyon system and the plateau read as whole features. Where a cell is low at both scales it is a canyon; high at both, a mountain top or high ridge; high at 500 m but low at 2 km, a local ridge in a valley.

The bundled Weiss 10-Class Landform system expects neighborhood-standardized TPI, and these rasters are raw, so the run uses a custom system built in the Classification System Builder: the Weiss system duplicated, every TPI criterion switched to raw units, the small-neighborhood thresholds set to −100 and +100 m, the large-neighborhood thresholds to −200 and +200 m, and the slope threshold to 6°.

The Classification System Builder with a landform system named 10-Class Landform, Raw TPI, Grand Canyon, slope units Degrees, the ten Weiss classes with their colors, and the criteria for the Plains class: tpi_small raw greater than -100 and less than 100, tpi_large raw greater than -200 and less than 200, slope in degrees less than or equal to 6
The custom system, with the Plains class selected: both TPIs near zero in raw units and a slope of no more than 6°. The other nine classes use the same ±100 and ±200 m breaks in the combinations of the Weiss table above.
The Landform Classification pane in Use Existing TPI and Slope Rasters mode: existing small-neighborhood TPI Grand Canyon: Raw TPI Units, 500m with Declare Raw (elevation units); existing large-neighborhood TPI Grand Canyon: Raw TPI Units, 2km with Declare Raw (elevation units); existing slope raster Grand_Canyon_Slope with Declare Degrees; classification system 10-Class Landform, Raw TPI, Grand Canyon; output Grand_Canyon_Landforms
The pane in existing-rasters mode. The on-the-fly group does not appear; each raster has its Declare dropdown filled in from the metadata our tools wrote, and the custom system's units agree with them, so there is no warning.
The ten-class landform raster of the Grand Canyon over a hillshade with its legend: canyons and deeply incised streams in dark blue tracing every drainage, midslope and upland drainages in lighter blues, U-shaped valleys in gray-green, plains in pale yellow on the plateau tops, open slopes in olive across most of the area, upper slopes and mesas in tan along the plateau edges, and local ridges, midslope ridges and mountain tops in oranges and dark red on the spurs and rims; a 10 kilometer scale bar
The ten landform classes. The drainages come out as canyons and deeply incised streams in dark blue, the spurs and rims between them as ridges in oranges and red, the plateau tops as plains in pale yellow, their edges as upper slopes and mesas in tan, and the canyon walls as open slopes in olive.

The tool holds the whole raster in memory at once, so the memory it needs grows with the number of cells. On most rasters that is no concern. On a very large one the tool may need more memory than your computer has free, and then one of two things happens: Windows starts using the disk as overflow memory and the tool slows to a crawl, or the tool stops with an out-of-memory error. There is no fixed limit; it depends on how much memory your computer has free. If a raster is too large, clip it to the area you need first.

ModelBuilder

A ModelBuilder diagram: Grand Canyon: Raw TPI Units, 500m, Grand Canyon: Raw TPI Units, 2km and Grand_Canyon_Slope all feeding Landform Classification, producing Grand_Canyon_Landforms and the three optional save outputs
The existing-rasters run as a model: three inputs, the two TPIs and the slope. Calculating on the fly needs only the DEM, and the three save outputs then carry the generated rasters.

In a model the three optional save outputs are ordinary derived rasters, so a downstream tool, including this one in existing-rasters mode, can take them as inputs.

Parameters

LabelExplanationData type
TPI and slope sourceRequired · tpi_source Calculate TPI and Slope on-the-fly from DEM (default) computes both TPIs and the slope from the DEM with the settings in the first group; Use Existing TPI and Slope Rasters classifies rasters you already have, as they are. String
Input elevation raster (DEM)Optional · in_raster Single-band DEM, projected or geographic; required when calculating on the fly, hidden otherwise. Raster Layer or Dataset
Small neighborhood shapeRequired · sm_shape Circle (all cells within the radius) or Annulus (a ring between an inner and outer radius) for the small-scale TPI. Default Circle. String
Small neighborhood radiusRequired · sm_outer The (outer) radius of the small neighborhood: the local scale. Default 3. Double
Small neighborhood inner radius (annulus only)Optional · sm_inner For an annulus, cells nearer than this are excluded. Ignored for a circle. Double
Small neighborhood radius unitsRequired · sm_units Cells, or a ground unit (meters, kilometers, feet, miles) converted from the cell size; per row on the spheroid for geographic DEMs. Default Cells. String
Small-neighborhood TPI typeRequired · tpi_type_small Raw (elevation units), Neighborhood standard deviation or Percentile for the small scale. Defaults to what the system expects for its small TPI; a mismatch warns and still runs. String
Large neighborhood shapeRequired · lg_shape Circle or Annulus for the large-scale TPI. String
Large neighborhood radiusRequired · lg_outer The (outer) radius of the large neighborhood: the broad context. Make it clearly larger than the small radius; the tool warns if it is not, when the two are in comparable units. Default 15. Double
Large neighborhood inner radius (annulus only)Optional · lg_inner For an annulus, cells nearer than this are excluded. Double
Large neighborhood radius unitsRequired · lg_units Cells or a ground unit, as for the small neighborhood. Default Cells. String
Large-neighborhood TPI typeRequired · tpi_type_large The TPI type for the large scale, chosen independently of the small one; defaults to what the system expects for its large TPI. String
Elevation unitsOptional · elev_units Meters or feet, for the slope calculation; detected and locked when the DEM has a vertical coordinate system. String
Slope method (projected DEMs)Optional · slope_method Planar (matches Esri's Slope tool) or Geodesic; geographic DEMs are always geodesic. String
Slope output unitsRequired · slope_units Degrees or percent rise; defaults to the system's assumption and warns on a mismatch. Stamped into any saved slope raster. String
Save generated small-neighborhood TPI (optional)Optional · save_tpi_small Keep the intermediate small TPI raster, stamped with its type and radius. Blank keeps it in memory only. Raster Dataset
Save generated large-neighborhood TPI (optional)Optional · save_tpi_large Keep the intermediate large TPI raster, stamped with its type and radius. Raster Dataset
Save generated slope raster (optional)Optional · save_slope Keep the intermediate slope raster, stamped with its units. Raster Dataset
Existing small-neighborhood TPIOptional · in_tpi_small When using existing rasters: the small-scale TPI to classify, as is. Must have the same number of rows and columns as the other rasters; the tool checks the dimensions, not the extent. Its type and radius are read from its metadata when our tools wrote it. Raster Layer or Dataset
Declare small-neighborhood TPI type (optional, for warnings)Optional · declare_tpi_type_small What kind of TPI the small raster holds, when its metadata does not say; used only for the compatibility warning. String
Existing large-neighborhood TPIOptional · in_tpi_large When using existing rasters: the large-scale TPI to classify, as is; its radius is compared with the small raster's when both are stamped. Raster Layer or Dataset
Declare large-neighborhood TPI type (optional, for warnings)Optional · declare_tpi_type_large What kind of TPI the large raster holds, when its metadata does not say; warnings only. String
Existing slope rasterOptional · in_slope When using existing rasters: the slope raster; required when the system uses slope. Raster Layer or Dataset
Declare slope units (optional, for warnings)Optional · declare_slope_units Degrees or percent for an existing slope raster, when its metadata does not say; warnings only. String
Classification systemRequired · system The saved landform system to apply: thresholds, names and colors. The bundled default is the Weiss 10-class. Picking one sets the two TPI-type and the slope-unit defaults. String
Output landform rasterRequired · out_raster Integer class raster with a Value / Class_Name table and the system's color map. Cells matching no class are unclassified. Any unit or scale warnings are written into its metadata. Raster Dataset

Python

import arcpy
arcpy.ImportToolbox(r"C:\path\to\JennessEnterprisesTools.pyt")  # your install path

# Compute both TPIs and the slope on the fly from a DEM.
arcpy.jenness.LandformClassification(
    tpi_source="Calculate TPI and Slope on-the-fly from DEM",
    in_raster=r"D:\flagstaff.gdb\DEM_Flagstaff_Area",
    sm_shape="Circle", sm_outer=100, sm_inner=0, sm_units="Meters",
    tpi_type_small="Neighborhood standard deviation",
    lg_shape="Circle", lg_outer=1000, lg_inner=0, lg_units="Meters",
    tpi_type_large="Neighborhood standard deviation",
    elev_units="Meters", slope_method="Geodesic", slope_units="Degrees",
    save_tpi_small=r"D:\flagstaff.gdb\TPI_100m",
    save_tpi_large=r"D:\flagstaff.gdb\TPI_1000m",
    save_slope=r"D:\flagstaff.gdb\Slope_Degrees",
    system="Weiss 10-Class Landform",
    out_raster=r"D:\flagstaff.gdb\Landform")

# Classify rasters that already exist, as they are. The declare_*
# arguments are optional; rasters made by these tools carry their
# type and units in their metadata.
arcpy.jenness.LandformClassification(
    tpi_source="Use Existing TPI and Slope Rasters",
    in_tpi_small=r"D:\flagstaff.gdb\TPI_100m",
    declare_tpi_type_small="Neighborhood standard deviation",
    in_tpi_large=r"D:\flagstaff.gdb\TPI_1000m",
    declare_tpi_type_large="Neighborhood standard deviation",
    in_slope=r"D:\flagstaff.gdb\Slope_Degrees",
    declare_slope_units="Degrees",
    system="Weiss 10-Class Landform",
    out_raster=r"D:\flagstaff.gdb\Landform2")

The list-driven parameters take these strings exactly: tpi_source is "Calculate TPI and Slope on-the-fly from DEM" or "Use Existing TPI and Slope Rasters"; sm_shape and lg_shape are "Circle" or "Annulus"; sm_units and lg_units are "Cells", "Meters", "Kilometers", "Feet" or "Miles"; tpi_type_small and tpi_type_large are "Raw (elevation units)", "Neighborhood standard deviation" or "Percentile", and may differ; elev_units is "Meters" or "Feet"; slope_method is "Planar" or "Geodesic"; slope_units and declare_slope_units are "Degrees" or "Percent"; the two declare_tpi_type arguments add "DEM-scale standard deviation" to the three TPI types; and system is the name of any landform system in the store, bundled or your own. The names of the systems on your computer are listed in the Classification System Builder; they are also the "name" entries of the JSON files in %LOCALAPPDATA%\JennessEnterprises\WildlifeTools\classification_systems\, but if you look them up there, take care not to change anything: an edited file can leave a system unreadable.

Recommended citation

Jenness, J. 2026. Landform Classification. Wildlife and Forestry Tools add-in for ArcGIS Pro, v. 1.99 (September 2026). Jenness Enterprises. Available at: https://github.com/JeffJenness/Wildlife_Tools.

Credits and references

By Jeff Jenness, Jenness Enterprises (www.jennessent.com), modernizing the landform classification of his Topographic Position Index extension for ArcView 3.x. The method is that of Andrew Weiss's 2001 poster, and the bundled ten-class system is adapted from his classification system.

Licensing information

Works at every ArcGIS Pro license level (Basic, Standard, Advanced). No extension licenses are required; the two TPIs and the slope are computed internally, without Spatial Analyst.