API reference¶
Classification API¶
pedotri.classify¶
pedotri.classify ¶
classify(
sand: float | int,
clay: float | int,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[False] = ...,
units: str = ...,
) -> str | None
classify(
sand: ArrayLike,
clay: ArrayLike,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[False] = ...,
units: str = ...,
) -> list[str | None]
classify(
sand: float | int,
clay: float | int,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[True],
units: str = ...,
) -> ClassifyResult
classify(
sand: ArrayLike,
clay: ArrayLike,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[True],
units: str = ...,
) -> list[ClassifyResult]
classify(
value: float | int,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[False] = ...,
units: str = ...,
) -> str | None
classify(
value: ArrayLike,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[False] = ...,
units: str = ...,
) -> list[str | None]
classify(
value: float | int,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[True],
units: str = ...,
) -> ClassifyResult
classify(
value: ArrayLike,
classification: str | Classification,
*,
locale: Locale | None = ...,
detailed: Literal[True],
units: str = ...,
) -> list[ClassifyResult]
classify(
*args: Any, **kwargs: Any
) -> (
str
| None
| list[str | None]
| ClassifyResult
| list[ClassifyResult]
)
Classify one or many soil texture points.
The number and meaning of fraction arguments depends on the chosen
classification's :attr:~pedotri.schema.Classification.axes. The
function accepts three calling styles:
Positional, axes-ordered::
pedotri.classify(70, 20, "USDA") # sand=70, clay=20
pedotri.classify(10, "KACHINSKY") # physical_clay=10
Keyword fractions with positional classification::
pedotri.classify(sand=70, clay=20, classification="USDA")
Mixed::
pedotri.classify(70, classification="USDA", clay=20)
The argument shapes are documented through the overload signatures above. In short:
- fraction values — one positional argument per axis of the
chosen classification, in axis order. Each value is either a
scalar percentage in [0, 100] or an array-like of percentages.
Fractions may also be passed by axis name as keyword arguments
(
sand=...,clay=...,physical_clay=...). - classification — last positional argument, or the
classification=keyword. May be a classification key string (e.g."USDA") or a :class:Classificationinstance. - locale — optional locale tag. When provided, class names
are localized via the fallback chain (
fr-FR→fr→en); when omitted, results use the stable class keys. - detailed — when
True, returns :class:ClassifyResultobjects with name, group, parent, and signed distance-to-boundary rather than bare strings. - units — keyword.
"%"(default),"g/kg", or"g/g". Applied uniformly to every fraction input. Use"g/kg"when your lab reports sand / clay / silt as g/kg (common in European soil chemistry), or"g/g"for the 0-1 mass-fraction convention. _uncertainty — optional keyword per axis (e.g.sand_uncertainty,clay_uncertainty). Accepts a :class:~pedotri.uncertainty.Quantiles(recommended), a scalar or array σ, or — for backwards compatibility — a bare(Q0.05, Q0.95)2-tuple (emits aDeprecationWarning). When any uncertainty kwarg is supplied,detailedis automatically promoted toTrueso probabilities and confidence can be returned, and the function returns a :class:ClassifyResultregardless of howdetailedwas passed.- method —
"distance"(default) or"monte_carlo". Only relevant when uncertainty kwargs are supplied. The distance method compares boundary distance to the input σ for a single confidence score; Monte Carlo drawsn_samplesrealizations and returns a full probability distribution. - n_samples — int, default
1000. Number of Monte Carlo draws per input point. - seed — optional int or
np.random.Generator. Seeds the Monte Carlo sampler for reproducibility.
Returns the matched class key (or localized name, or
:class:ClassifyResult) for scalar input, or a list of those
values for array-like input. None is returned for any point
that lies outside every class polygon / interval.
Raises :class:InvalidInputError if fraction arrays have
mismatched shapes or contain NaN / out-of-range values, or if the
wrong number of fractions was provided.
Raises :class:UnknownClassificationError if classification
is a string that is not registered.
pedotri.ClassifyResult¶
pedotri.ClassifyResult
dataclass
¶
Detailed classification of a single point.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str | None
|
The matched class's stable key, or |
name |
str
|
The localized class name (or |
group |
str | None
|
Coarse grouping of the class (e.g. |
parent |
str | None
|
Hierarchical parent class key if defined. |
distance |
float
|
Signed Euclidean distance to the matched class boundary
in the axis space. Positive means strictly inside; the larger
the magnitude, the deeper the point sits inside its class.
For 1-D classifications, this is the distance to the nearest
interval endpoint. |
probabilities |
dict[str, float] | None
|
Mapping from class key to posterior probability
when uncertainty information was supplied. |
entropy |
float | None
|
Shannon entropy of :attr: |
confidence |
float | None
|
Single scalar in |
unclassified_probability |
float | None
|
Fraction of Monte Carlo samples that
fell outside every class polygon. |
to_dict ¶
Return a JSON-serializable dict representation.
nan is mapped to None so the result encodes cleanly with
the standard library json module. Uncertainty-related fields
are included only when populated, to keep the deterministic
output unchanged.
pedotri.list_classifications¶
pedotri.list_classifications ¶
Return the sorted list of all registered classification keys.
pedotri.get_classification¶
pedotri.get_classification ¶
Return the registered classification for key (case-insensitive).
Built-ins and entry-point classifications are loaded lazily on first
access. Raises :class:UnknownClassificationError if the key is not
registered.
pedotri.register_classification¶
pedotri.register_classification ¶
register_classification(
source: str
| Path
| bytes
| dict[str, Any]
| Classification,
*,
overwrite: bool = False,
) -> Classification
Register a custom classification.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
str | Path | bytes | dict[str, Any] | Classification
|
A TOML path, raw TOML bytes, a pre-parsed dict, or an
already-constructed :class: |
required |
overwrite
|
bool
|
If |
False
|
Returns:
| Type | Description |
|---|---|
Classification
|
The (validated) :class: |
pedotri.unregister_classification¶
pedotri.unregister_classification ¶
Remove a previously registered classification.
No-op if the key isn't registered. Useful in tests.
pedotri.load_classification¶
pedotri.load_classification ¶
Load a :class:Classification from TOML.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
str | Path | bytes | dict[str, Any]
|
Either a path to a |
required |
Returns:
| Type | Description |
|---|---|
Classification
|
A validated :class: |
Raises:
| Type | Description |
|---|---|
ClassificationError
|
If the document is missing required fields or contains invalid data. |
FileNotFoundError
|
If a path is given that does not exist. |
Data model¶
pedotri.Classification¶
pedotri.Classification
dataclass
¶
A complete soil texture classification system.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
Uppercase identifier (e.g. |
axes |
tuple[str, ...]
|
Pair of particle-size fractions used as the x and y axes,
e.g. |
classes |
tuple[TextureClass, ...]
|
Tuple of :class: |
names |
dict[Locale, str]
|
Localized names of the classification itself (for UI display). |
default_locale |
Locale
|
Locale to use when none is explicitly requested. |
reference |
str | None
|
Bibliographic reference for the polygon definitions. |
url |
str | None
|
Optional canonical URL for the reference. |
description |
str | None
|
Optional longer description of scope and intended use. |
pedotri.TextureClass¶
pedotri.TextureClass
dataclass
¶
A single named texture class within a classification.
A class is either a polygon in 2-D space (when the parent
classification has two axes, e.g. USDA's sand-clay plane) or an
interval on a single axis (when the classification is 1-D, e.g.
Kachinsky's physical clay fraction). Exactly one of
:attr:vertices and :attr:interval must be set, matching the
parent classification's :attr:Classification.axes length.
Treat instances as immutable after construction.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
Stable machine identifier. Used as the return value of
:func: |
vertices |
FloatArray | None
|
(N, 2) float array of polygon vertices in the
(axis_x, axis_y) plane. Coordinates are percentages in
[0, 100]. Closure is implicit. Set this for 2-D classes;
leave :attr: |
interval |
tuple[float, float] | None
|
|
names |
dict[Locale, str]
|
Mapping of locale tag → localized display name. |
group |
str | None
|
Optional coarse grouping (e.g. |
parent |
str | None
|
Optional parent class key for hierarchical classifications. |
Plotting¶
pedotri.plot.render_svg¶
pedotri.plot.render_svg ¶
render_svg(
classification: str | Classification,
*,
points: Sequence[Sequence[float]] | None = None,
point_labels: Sequence[str] | None = None,
locale: str | None = None,
title: str | None = None,
width: int = 720,
show_legend: bool = True,
show_grid: bool = True,
) -> str
Render a soil texture diagram as a standalone SVG string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
classification
|
str | Classification
|
Classification key (e.g. |
required |
points
|
Sequence[Sequence[float]] | None
|
Optional list of (sand, clay) pairs for 2-D classifications, or (value,) / scalars for 1-D. Drawn as overlay markers. |
None
|
point_labels
|
Sequence[str] | None
|
Optional labels for each marker. |
None
|
locale
|
str | None
|
Locale tag for class names in the legend; falls back to the classification's default locale. |
None
|
title
|
str | None
|
Optional title rendered above the diagram. |
None
|
width
|
int
|
SVG viewport width in pixels. |
720
|
show_legend
|
bool
|
Include a class legend to the right of the diagram. |
True
|
show_grid
|
bool
|
For 2-D, draw the 10 % interior grid lines. |
True
|
Returns:
| Type | Description |
|---|---|
str
|
SVG document as a string. |
pedotri.plot.TextureDiagram¶
pedotri.plot.TextureDiagram ¶
pedotri.plot.render_mpl¶
pedotri.plot.mpl.render_mpl ¶
render_mpl(
classification: str | Classification,
*,
points: Sequence[Sequence[float]] | None = None,
point_labels: Sequence[str] | None = None,
locale: str | None = None,
title: str | None = None,
show_legend: bool = True,
show_grid: bool = True,
figsize: tuple[float, float] = (8, 7),
) -> Figure
Render a texture diagram as a :class:matplotlib.figure.Figure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
classification
|
str | Classification
|
Classification key or instance. |
required |
points
|
Sequence[Sequence[float]] | None
|
Optional (sand, clay) overlay points for 2-D classifications, or 1-tuples / scalars for 1-D. |
None
|
point_labels
|
Sequence[str] | None
|
Optional labels printed beside each marker. |
None
|
locale
|
str | None
|
Locale for class names in tooltips and legend. |
None
|
title
|
str | None
|
Optional figure title. |
None
|
show_legend
|
bool
|
Show class colour legend. |
True
|
show_grid
|
bool
|
For 2-D, draw 10 % interior gridlines. |
True
|
figsize
|
tuple[float, float]
|
(width, height) inches passed to |
(8, 7)
|
Returns:
| Type | Description |
|---|---|
Figure
|
Configured |
Raises:
| Type | Description |
|---|---|
ModuleNotFoundError
|
If matplotlib is not installed. |
pedotri.plot.render_plotly¶
pedotri.plot.plotly_backend.render_plotly ¶
render_plotly(
classification: str | Classification,
*,
points: Sequence[Sequence[float]] | None = None,
point_labels: Sequence[str] | None = None,
locale: str | None = None,
title: str | None = None,
width: int = 720,
height: int = 640,
) -> Any
Render a texture diagram as a :class:plotly.graph_objects.Figure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
classification
|
str | Classification
|
Classification key or instance. |
required |
points
|
Sequence[Sequence[float]] | None
|
Optional (sand, clay) overlay points for 2-D, or 1-tuples / scalars for 1-D. |
None
|
point_labels
|
Sequence[str] | None
|
Optional labels shown alongside markers. |
None
|
locale
|
str | None
|
Locale for class names in tooltips and legend. |
None
|
title
|
str | None
|
Optional figure title. |
None
|
width
|
int
|
Pixel width. |
720
|
height
|
int
|
Pixel height. |
640
|
Returns:
| Type | Description |
|---|---|
Any
|
A |
Any
|
|
Raises:
| Type | Description |
|---|---|
ModuleNotFoundError
|
If plotly is not installed. |
Pedotransfer functions¶
pedotri.ptf.saxton_rawls¶
pedotri.ptf.saxton_rawls ¶
Saxton & Rawls (2006) pedotransfer function.
Estimates soil-water retention and saturated hydraulic conductivity from sand %, clay %, and organic matter %. Optionally adjusts for bulk-density compaction via a density factor and for gravel content.
The implementation follows the equations in:
Saxton, K.E. & Rawls, W.J. (2006). Soil water characteristic
estimates by texture and organic matter for hydrologic solutions.
Soil Science Society of America Journal, 70(5): 1569-1578.
Inputs are percentages (0-100) to match :func:pedotri.classify;
the formulas use fractions internally.
SaxtonRawlsResult
dataclass
¶
Soil-water characteristics estimated by Saxton-Rawls (2006).
All water-content quantities are volumetric (cm³ water / cm³ bulk soil) — i.e. fractions in [0, 1].
Attributes:
| Name | Type | Description |
|---|---|---|
wilting_point |
float
|
Water content at 1500 kPa suction (θ_1500), the permanent wilting point. |
field_capacity |
float
|
Water content at 33 kPa suction (θ_33), the conventional drained-equilibrium field capacity for agronomic soils. |
saturation |
float
|
Water content at saturation (θ_s). |
available_water |
float
|
Plant-available water = |
saturated_conductivity |
float
|
Saturated hydraulic conductivity (K_s) in mm/h. |
bulk_density |
float
|
Normal-density bulk density (g/cm³). |
air_entry_tension |
float
|
Air-entry tension (bubbling pressure) ψ_e in kPa. |
saxton_rawls ¶
saxton_rawls(
sand: ScalarOrArrayLike,
clay: ScalarOrArrayLike,
organic_matter: ScalarOrArrayLike = 1.0,
*,
density_factor: float = 1.0,
units: str = "%",
) -> SaxtonRawlsResult | list[SaxtonRawlsResult]
Compute soil hydraulic properties from texture and organic matter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sand
|
ScalarOrArrayLike
|
Sand fraction. Default units: percent in [0, 100]. Scalar or array-like. |
required |
clay
|
ScalarOrArrayLike
|
Clay fraction. Default units: percent in [0, 100]. Scalar or array-like. |
required |
organic_matter
|
ScalarOrArrayLike
|
Organic-matter fraction (not organic carbon — see note below). Default units: percent in [0, 100]. Default value 1.0 % which is typical for agricultural mineral soils. |
1.0
|
density_factor
|
float
|
Compaction-adjustment multiplier on the
regression's normal bulk density (Saxton & Rawls 2006,
Eq. 6-7). Default |
1.0
|
units
|
str
|
Units of the |
'%'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
SaxtonRawlsResult | list[SaxtonRawlsResult]
|
class: |
SaxtonRawlsResult | list[SaxtonRawlsResult]
|
results for array inputs. |
Raises:
| Type | Description |
|---|---|
InvalidInputError
|
If inputs are out of range or have mismatched
shapes, or if |
Note
Saxton-Rawls 2006 expects organic matter, but most lab reports
give organic carbon. Convert with
:func:pedotri.units.organic_carbon_to_organic_matter (Van
Bemmelen factor 1.724) before calling.
pedotri.ptf.SaxtonRawlsResult¶
pedotri.ptf.SaxtonRawlsResult
dataclass
¶
Soil-water characteristics estimated by Saxton-Rawls (2006).
All water-content quantities are volumetric (cm³ water / cm³ bulk soil) — i.e. fractions in [0, 1].
Attributes:
| Name | Type | Description |
|---|---|---|
wilting_point |
float
|
Water content at 1500 kPa suction (θ_1500), the permanent wilting point. |
field_capacity |
float
|
Water content at 33 kPa suction (θ_33), the conventional drained-equilibrium field capacity for agronomic soils. |
saturation |
float
|
Water content at saturation (θ_s). |
available_water |
float
|
Plant-available water = |
saturated_conductivity |
float
|
Saturated hydraulic conductivity (K_s) in mm/h. |
bulk_density |
float
|
Normal-density bulk density (g/cm³). |
air_entry_tension |
float
|
Air-entry tension (bubbling pressure) ψ_e in kPa. |
pedotri.ptf.wosten¶
pedotri.ptf.wosten ¶
Wösten et al. (1999) HYPRES pedotransfer function.
Estimates Mualem-van Genuchten water-retention and hydraulic-conductivity parameters from texture, organic matter, bulk density, and a topsoil/subsoil indicator. The implementation follows the continuous PTF of:
Wösten, J.H.M., Lilly, A., Nemes, A., Le Bas, C. (1999). Development
and use of a database of hydraulic properties of European soils.
Geoderma 90(3-4): 169-185.
The residual water content theta_r is fixed at 0.01, following the HYPRES convention.
WostenResult
dataclass
¶
Mualem-van Genuchten parameters from Wösten 1999.
The van Genuchten water-retention function is::
theta(h) = theta_r + (theta_s - theta_r) / [1 + (alpha*h)^n]^m
with m = 1 - 1/n
The Mualem unsaturated hydraulic-conductivity function is::
K(theta) = K_s * S_e^L * [1 - (1 - S_e^(1/m))^m]^2
with S_e = (theta - theta_r) / (theta_s - theta_r)
Attributes:
| Name | Type | Description |
|---|---|---|
theta_r |
float
|
Residual water content (m³/m³). Fixed at 0.01 in HYPRES. |
theta_s |
float
|
Saturated water content (m³/m³). |
alpha |
float
|
Van Genuchten alpha (1/cm). |
n |
float
|
Van Genuchten n (dimensionless, > 1). |
saturated_conductivity |
float
|
K_s in cm/day. |
l |
float
|
Mualem pore-connectivity parameter, bounded by Wösten's
logistic transform to |
wosten ¶
wosten(
sand: ScalarOrArrayLike,
silt: ScalarOrArrayLike,
clay: ScalarOrArrayLike,
*,
organic_matter: ScalarOrArrayLike = 1.0,
bulk_density: ScalarOrArrayLike = 1.4,
topsoil: bool = True,
units: str = "%",
) -> WostenResult | list[WostenResult]
Estimate Mualem-van Genuchten parameters via Wösten 1999.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sand
|
ScalarOrArrayLike
|
Sand fraction. Default units: percent in [0, 100]. Used only for input validation; the PTF uses silt and clay explicitly. |
required |
silt
|
ScalarOrArrayLike
|
Silt fraction. Default units: percent. Must be strictly
positive — the PTF contains |
required |
clay
|
ScalarOrArrayLike
|
Clay fraction. Default units: percent. Must be strictly
positive — the PTF contains |
required |
organic_matter
|
ScalarOrArrayLike
|
Organic-matter fraction (not organic carbon;
see :func: |
1.0
|
bulk_density
|
ScalarOrArrayLike
|
Dry bulk density (g/cm³). Default 1.4. Always in
g/cm³ regardless of the |
1.4
|
topsoil
|
bool
|
True if the sample is a topsoil horizon, False for subsoil. Affects alpha, n, and K_s. |
True
|
units
|
str
|
Units of |
'%'
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
WostenResult | list[WostenResult]
|
class: |
pedotri.ptf.WostenResult¶
pedotri.ptf.WostenResult
dataclass
¶
Mualem-van Genuchten parameters from Wösten 1999.
The van Genuchten water-retention function is::
theta(h) = theta_r + (theta_s - theta_r) / [1 + (alpha*h)^n]^m
with m = 1 - 1/n
The Mualem unsaturated hydraulic-conductivity function is::
K(theta) = K_s * S_e^L * [1 - (1 - S_e^(1/m))^m]^2
with S_e = (theta - theta_r) / (theta_s - theta_r)
Attributes:
| Name | Type | Description |
|---|---|---|
theta_r |
float
|
Residual water content (m³/m³). Fixed at 0.01 in HYPRES. |
theta_s |
float
|
Saturated water content (m³/m³). |
alpha |
float
|
Van Genuchten alpha (1/cm). |
n |
float
|
Van Genuchten n (dimensionless, > 1). |
saturated_conductivity |
float
|
K_s in cm/day. |
l |
float
|
Mualem pore-connectivity parameter, bounded by Wösten's
logistic transform to |
Particle-size conversions¶
pedotri.psd.convert¶
pedotri.psd.convert ¶
convert(
sand: ScalarOrArrayLike,
silt: ScalarOrArrayLike,
clay: ScalarOrArrayLike,
*,
source: str,
target: str,
units: str = "%",
) -> tuple[FloatArray, FloatArray, FloatArray]
Convert (sand, silt, clay) fractions between particle-size standards.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sand
|
ScalarOrArrayLike
|
Sand fraction under the |
required |
silt
|
ScalarOrArrayLike
|
Silt fraction under the |
required |
clay
|
ScalarOrArrayLike
|
Clay fraction. Unchanged across all supported standards (the silt/clay boundary is universally 0.002 mm). |
required |
source
|
str
|
Particle-size standard name of the input, one of
:data: |
required |
target
|
str
|
Standard to convert to, same key set. |
required |
units
|
str
|
Units of the three fraction arguments. One of |
'%'
|
Returns:
| Type | Description |
|---|---|
FloatArray
|
|
FloatArray
|
percent. Outputs are always 1-D numpy arrays; pass |
FloatArray
|
single-element arrays through |
tuple[FloatArray, FloatArray, FloatArray]
|
scalars. |
Raises:
| Type | Description |
|---|---|
InvalidInputError
|
For unknown standards, out-of-range percentages, or fractions whose sum deviates from 100 % by more than 0.5 percentage points. |
Note
Conversion is not exactly reversible: convert(usda → isss → usda)
generally differs from the input by a percent or two, reflecting
the limitations of a single log-linear interior model.
pedotri.psd.interpolate_psd¶
pedotri.psd.interpolate_psd ¶
interpolate_psd(
sieve_sizes_mm: FloatArray,
cumulative_pct_passing: FloatArray,
target_size_mm: float,
) -> float
Interpolate a particle-size distribution onto a target sieve.
Given a measured PSD as (sieve_sizes, % passing each sieve), return
the % of mass that would pass a sieve at target_size_mm,
interpolating log-linearly between the nearest measured points.
This is the building block for arbitrary cutoff conversions when a richer PSD than the three-point sand/silt/clay split is available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sieve_sizes_mm
|
FloatArray
|
Strictly-increasing sieve sizes in mm. |
required |
cumulative_pct_passing
|
FloatArray
|
% of sample mass finer than each sieve,
same length as |
required |
target_size_mm
|
float
|
Sieve size to interpolate onto, in mm. |
required |
Returns:
| Type | Description |
|---|---|
float
|
% of sample mass finer than |
Raises:
| Type | Description |
|---|---|
InvalidInputError
|
For mismatched shapes, non-monotonic inputs, or a target outside the measured range. |
pedotri.psd.SAND_SILT_CUTOFF_MM¶
pedotri.psd.SAND_SILT_CUTOFF_MM
module-attribute
¶
SAND_SILT_CUTOFF_MM: dict[str, float] = {
"USDA": 0.05,
"FAO": 0.05,
"ISSS": 0.02,
"INTERNATIONAL": 0.02,
"KA5": 0.063,
}
Raster (GeoTIFF) classification¶
pedotri.raster.classify_array¶
pedotri.raster.classify_array ¶
classify_array(
sand: FloatArray | ndarray,
clay: FloatArray | ndarray,
*,
classification: str | Classification,
units: str = "%",
mask: ndarray | None = None,
sum_tolerance: float = 5.0,
) -> tuple[np.ndarray, list[str]]
Classify a raster of sand / clay fractions into integer codes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sand
|
FloatArray | ndarray
|
Sand fraction raster (any shape). Default units are
percent; pass |
required |
clay
|
FloatArray | ndarray
|
Clay fraction raster, same shape as |
required |
classification
|
str | Classification
|
A registered 2-axis classification key
( |
required |
units
|
str
|
Units of the input rasters. |
'%'
|
mask
|
ndarray | None
|
Optional boolean array, same shape as |
None
|
sum_tolerance
|
float
|
A pixel whose |
5.0
|
Returns:
| Type | Description |
|---|---|
ndarray
|
A |
list[str]
|
same shape as |
tuple[ndarray, list[str]]
|
|
tuple[ndarray, list[str]]
|
the list of class keys in the order used by the codes — so |
tuple[ndarray, list[str]]
|
|
tuple[ndarray, list[str]]
|
when |
Raises:
| Type | Description |
|---|---|
InvalidInputError
|
For shape mismatches or unknown units. |
PedotriError
|
If the chosen classification has a single axis (1-D classifications are out of scope for raster classification — they would need a different input shape). |
pedotri.raster.classify_geotiff¶
pedotri.raster.classify_geotiff ¶
classify_geotiff(
sand: Path | str,
clay: Path | str,
*,
classification: str | Classification,
units: str = "%",
sum_tolerance: float = 5.0,
) -> tuple[np.ndarray, list[str], dict[str, Any]]
Read two GeoTIFFs, classify pixel-wise, return codes + profile.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sand
|
Path | str
|
Path to a single-band sand-fraction GeoTIFF. |
required |
clay
|
Path | str
|
Path to a single-band clay-fraction GeoTIFF in the same
CRS, resolution, and extent as |
required |
classification
|
str | Classification
|
Same as :func: |
required |
units
|
str
|
Units of both input rasters. Default |
'%'
|
sum_tolerance
|
float
|
Forwarded to :func: |
5.0
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
list[str]
|
dict with |
dict[str, Any]
|
sand raster's CRS / transform / size, ready to pass to |
tuple[ndarray, list[str], dict[str, Any]]
|
func: |
Raises:
| Type | Description |
|---|---|
ImportError
|
If the optional |
InvalidInputError
|
If the two rasters disagree on shape, CRS, or transform. |
pedotri.raster.write_classified_geotiff¶
pedotri.raster.write_classified_geotiff ¶
write_classified_geotiff(
path: Path | str,
codes: ndarray,
*,
profile: dict[str, Any],
keys: list[str],
colormap: dict[int, tuple[int, int, int, int]]
| None = None,
) -> None
Write a class-code raster as a GeoTIFF with class names + colors.
Output is a paletted uint8 GeoTIFF (the only dtype on which
GDAL/QGIS persist a color table). The in-memory NODATA_CODE
sentinel (-1, int16) is remapped to 255 on disk so the
file still has a clean nodata value. Class keys are written both
as band-level GDAL tags (class_<index>) and through rasterio's
color-table API, so QGIS and gdalinfo automatically pick up
the legend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Output path. |
required |
codes
|
ndarray
|
int16 array from :func: |
required |
profile
|
dict[str, Any]
|
rasterio profile to use for georeferencing. Typically
the third element returned by :func: |
required |
keys
|
list[str]
|
Class-key list returned alongside |
required |
colormap
|
dict[int, tuple[int, int, int, int]] | None
|
Optional mapping |
None
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
InvalidInputError
|
If |
pedotri.raster.smooth_codes¶
pedotri.raster.smooth_codes ¶
smooth_codes(
codes: ndarray,
*,
window: int = 3,
iterations: int = 1,
n_classes: int | None = None,
) -> np.ndarray
Apply a majority filter to a class-coded raster.
Replaces each pixel with the modal class index in a window x
window neighborhood (so isolated mis-classifications get
absorbed into their dominant surroundings — the standard
salt-and-pepper cleanup for remote-sensing class maps).
Implementation: one-hot expand the codes, run a uniform-box filter
on each class channel via :func:scipy.ndimage.uniform_filter,
and take the per-pixel argmax across classes. All vectorized
in C — orders of magnitude faster than a Python-callback mode
filter on large rasters.
The filter preserves :data:NODATA_CODE (-1) pixels: any
pixel that was nodata stays nodata; nodata pixels do not vote
for their neighbors' new class.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
codes
|
ndarray
|
int array of class codes (same convention as
:func: |
required |
window
|
int
|
Side length of the square neighborhood (odd, |
3
|
iterations
|
int
|
How many smoothing passes to apply. Each pass re-applies the same filter; two or three passes converge quickly for typical noise patterns. |
1
|
n_classes
|
int | None
|
Number of distinct class indices to consider.
Defaults to |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
Smoothed code array, same shape and dtype as |
Raises:
| Type | Description |
|---|---|
ImportError
|
If |
InvalidInputError
|
For invalid |
pedotri.raster.render_classified_png¶
pedotri.raster.render_classified_png ¶
render_classified_png(
path: Path | str,
codes: ndarray,
*,
keys: list[str],
title: str | None = None,
extent: tuple[float, float, float, float] | None = None,
xlabel: str | None = "longitude",
ylabel: str | None = "latitude",
figsize: tuple[float, float] = (8, 7),
dpi: int = 150,
cmap: str = "tab20",
) -> None
Render a class-coded raster as a PNG map with a side legend.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
Path | str
|
Output PNG path. |
required |
codes
|
ndarray
|
int array from :func: |
required |
keys
|
list[str]
|
Class-key list returned alongside |
required |
title
|
str | None
|
Optional figure title. |
None
|
extent
|
tuple[float, float, float, float] | None
|
|
None
|
xlabel
|
str | None
|
X-axis label. Defaults to |
'longitude'
|
ylabel
|
str | None
|
Y-axis label. Defaults to |
'latitude'
|
figsize
|
tuple[float, float]
|
matplotlib figure size in inches. |
(8, 7)
|
dpi
|
int
|
Output DPI; 150 is good for ~1500-px web images, 300 for print. |
150
|
cmap
|
str
|
A qualitative matplotlib colormap. |
'tab20'
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If matplotlib is not installed
( |
pedotri.raster.classified_to_features¶
pedotri.raster.classified_to_features ¶
classified_to_features(
codes: ndarray,
*,
keys: list[str],
transform: Any,
simplify_tolerance: float | None = None,
) -> list[dict[str, Any]]
Polygonize a class-coded raster into per-class vector features.
Adjacent pixels sharing the same class index are merged into a
single polygon (with holes where appropriate). nodata pixels
(-1) are excluded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
codes
|
ndarray
|
int array of class codes. |
required |
keys
|
list[str]
|
Class-key list returned alongside |
required |
transform
|
Any
|
rasterio |
required |
simplify_tolerance
|
float | None
|
If set, apply
:meth: |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
list[dict[str, Any]]
|
List of feature dicts ``{"geometry": shapely geom, |
|
list[dict[str, Any]]
|
"properties": {"class_id": int, "class_key": str}}``. Pass |
|
to |
list[dict[str, Any]]
|
func: |
list[dict[str, Any]]
|
feed directly into |
Raises:
| Type | Description |
|---|---|
ImportError
|
If rasterio or shapely is not installed
( |
pedotri.raster.write_features_shapefile¶
pedotri.raster.write_features_shapefile ¶
write_features_shapefile(
features: list[dict[str, Any]],
path: Path | str,
*,
crs: str = "EPSG:4326",
) -> None
Write features from :func:classified_to_features to a Shapefile.
Uses fiona directly so no GeoPandas dependency is required.
For GeoPackage or GeoJSON output, change the file extension —
fiona infers the driver from the path suffix.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
features
|
list[dict[str, Any]]
|
List of feature dicts from
:func: |
required |
path
|
Path | str
|
Output path. |
required |
crs
|
str
|
Coordinate reference system as an authority string
(e.g. |
'EPSG:4326'
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If shapely or fiona is not installed
( |
pedotri.raster.NODATA_CODE¶
Field-scale interpolation (pedotri.interp)¶
pedotri.interp.krige_samples¶
pedotri.interp.krige_samples ¶
krige_samples(
xs: Sequence[float] | ndarray,
ys: Sequence[float] | ndarray,
values: Sequence[float] | ndarray,
*,
bbox: tuple[float, float, float, float],
resolution: float | tuple[float, float],
variogram: VariogramModel = "spherical",
n_lags: int = 6,
) -> tuple[np.ndarray, np.ndarray, dict[str, Any]]
Ordinary-krige a single property on a regular grid.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
xs
|
Sequence[float] | ndarray
|
X coordinates of the N samples (1-D). |
required |
ys
|
Sequence[float] | ndarray
|
Y coordinates of the N samples (1-D, same length as |
required |
values
|
Sequence[float] | ndarray
|
Property values at each sample. Length-N, same order
as |
required |
bbox
|
tuple[float, float, float, float]
|
Output extent |
required |
resolution
|
float | tuple[float, float]
|
Output cell size. Either a single float (square
cells) or a tuple |
required |
variogram
|
VariogramModel
|
Variogram model name passed to pykrige. |
'spherical'
|
n_lags
|
int
|
Number of lag bins used for empirical variogram estimation. pykrige's default is 6; raise for >50 samples, lower for very small N. |
6
|
Returns:
| Type | Description |
|---|---|
ndarray
|
A |
ndarray
|
prediction with shape |
dict[str, Any]
|
|
tuple[ndarray, ndarray, dict[str, Any]]
|
larger means lower confidence). |
tuple[ndarray, ndarray, dict[str, Any]]
|
profile dict ( |
tuple[ndarray, ndarray, dict[str, Any]]
|
|
tuple[ndarray, ndarray, dict[str, Any]]
|
func: |
tuple[ndarray, ndarray, dict[str, Any]]
|
is classified. |
tuple[ndarray, ndarray, dict[str, Any]]
|
interpolator doesn't know what CRS the coordinates are in — |
tuple[ndarray, ndarray, dict[str, Any]]
|
set it on the returned profile before writing if you care. |
Raises:
| Type | Description |
|---|---|
ImportError
|
If pykrige is not installed
( |
InvalidInputError
|
For mismatched array lengths, fewer than three samples, or zero-area bbox. |
pedotri.interp.krige_sand_clay¶
pedotri.interp.krige_sand_clay ¶
krige_sand_clay(
samples: Sequence[dict[str, float]] | ndarray,
*,
bbox: tuple[float, float, float, float],
resolution: float | tuple[float, float],
variogram: VariogramModel = "spherical",
n_lags: int = 6,
mask_polygon: Any | None = None,
crs: str | None = None,
) -> tuple[np.ndarray, np.ndarray, dict[str, Any]]
Krige sand and clay independently from a single sample table.
This is the field-scale convenience function: given a list of in-
situ samples (each with x, y, sand %, clay %), it kriges both
fractions, optionally masks the result to a bounding polygon
(so cells outside the field become nodata), and returns rasters
suitable for :func:pedotri.raster.classify_array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
samples
|
Sequence[dict[str, float]] | ndarray
|
Either a list of dicts
|
required |
bbox
|
tuple[float, float, float, float]
|
Output extent |
required |
resolution
|
float | tuple[float, float]
|
Output cell size, same as :func: |
required |
variogram
|
VariogramModel
|
Variogram model name, same as :func: |
'spherical'
|
n_lags
|
int
|
Number of lag bins, same as :func: |
6
|
mask_polygon
|
Any | None
|
Optional shapely Polygon / MultiPolygon
defining the field boundary. Cells whose centers fall
outside the polygon are set to |
None
|
crs
|
str | None
|
Optional CRS authority string (e.g. |
None
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
ndarray
|
func: |
dict[str, Any]
|
.. code-block:: python codes, keys = classify_array(sand_grid, clay_grid, classification="USDA") |
Raises:
| Type | Description |
|---|---|
ImportError
|
If pykrige (or shapely, when |
InvalidInputError
|
For malformed inputs (see
:func: |
Benchmark utilities¶
pedotri.bench.run_soiltexture_benchmark¶
pedotri.bench.run_soiltexture_benchmark ¶
run_soiltexture_benchmark(
sizes: list[int] | None = None,
*,
classification: str = "USDA",
seed: int = 0,
repeat: int = 3,
check_agreement: bool = True,
) -> BenchmarkReport
Time pedotri vs. soiltexture on equivalent inputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sizes
|
list[int] | None
|
Sample counts to benchmark, e.g. |
None
|
classification
|
str
|
Pedotri classification key. Must be one of
|
'USDA'
|
seed
|
int
|
Random seed for input generation. |
0
|
repeat
|
int
|
Each timing is the minimum of |
3
|
check_agreement
|
bool
|
When |
True
|
Returns:
| Type | Description |
|---|---|
BenchmarkReport
|
class: |
BenchmarkReport
|
package is not importable — the pedotri timings are still |
BenchmarkReport
|
reported so a CI run without the optional dependency degrades |
BenchmarkReport
|
gracefully. |
pedotri.bench.BenchmarkReport¶
pedotri.bench.BenchmarkReport
dataclass
¶
pedotri.bench.BenchmarkRow¶
pedotri.bench.BenchmarkRow
dataclass
¶
Timing result for one (n_points, library) cell.
pedotri.bench.generate_inputs¶
pedotri.bench.generate_inputs ¶
Generate n valid (sand, clay) samples in [0, 100] with sand+clay ≤ 100.
The distribution is uniform over the triangular feasible region
{(s, c) : s ≥ 0, c ≥ 0, s + c ≤ 100}. This guarantees no
nonsense inputs (impossible silt) and reasonable class coverage.
Exceptions¶
pedotri.PedotriError¶
pedotri.PedotriError ¶
Bases: Exception
Base class for all pedotri exceptions.
pedotri.ClassificationError¶
pedotri.ClassificationError ¶
Bases: PedotriError
Raised when a classification definition is invalid.
pedotri.UnknownClassificationError¶
pedotri.UnknownClassificationError ¶
pedotri.InvalidInputError¶
pedotri.InvalidInputError ¶
Bases: PedotriError, ValueError
Raised when input arrays are malformed (shape mismatch, NaNs, out of range, etc.).