Mass-preserving equal-area quadratic splines for depth harmonization of soil profiles
Project description
mpspline
Python implementation of mass-preserving equal-area quadratic splines for harmonizing soil profiles to standard depth intervals.
Port of the mpspline2 R package by Lauren O'Brien, based on the method of Bishop et al. (1999), as generalized in Malone et al. (2009).
Installation
pip install mpspline
Quick Start
from mpspline import mpspline
# Single profile
result = mpspline({
'horizons': [
{'hzname': 'A', 'upper': 0, 'lower': 20, 'clay': 24.5},
{'hzname': 'B', 'upper': 20, 'lower': 50, 'clay': 35.2},
]
}, output_type='wide')
print(result) # {'clay_0_5': 21.4, 'clay_5_15': 27.8, ...}
Usage
Pass a dict for a single profile or a list for multiple profiles.
1. Single Profile (Wide Format)
from mpspline import mpspline
# Single profile (returns dict)
result = mpspline({
'cokey': 12345,
'horizons': [
{'hzname': 'A', 'upper': 0, 'lower': 20, 'clay': 24.5},
{'hzname': 'B', 'upper': 20, 'lower': 50, 'clay': 35.2},
]
}, output_type='wide')
print(result)
# {'cokey': 12345, 'clay_0_5': 22.6, 'clay_5_15': 24.1, 'clay_15_30': 29.9, ...}
2. Multiple Profiles (Long Format - Default)
profiles = [
{
'cokey': 1001,
'horizons': [
{'hzname': 'A', 'upper': 0, 'lower': 15, 'clay': 18.5},
{'hzname': 'Bt1', 'upper': 15, 'lower': 45, 'clay': 35.0},
{'hzname': 'Bt2', 'upper': 45, 'lower': 80, 'clay': 32.5},
]
},
{
'cokey': 1002,
'horizons': [
{'hzname': 'Ap', 'upper': 0, 'lower': 20, 'clay': 15.2},
{'hzname': 'Bw', 'upper': 20, 'lower': 50, 'clay': 28.4},
{'hzname': 'C', 'upper': 50, 'lower': 100, 'clay': 25.0},
]
},
]
# Returns DataFrame with columns: [cokey, var_name, upper, lower, value]
df_long = mpspline(profiles, var_name=['clay'])
print(df_long[['cokey', 'var_name', 'upper', 'lower', 'value']].head())
Output:
cokey var_name upper lower value
1001 clay 0 5 16.168706
1001 clay 5 15 19.762784
1001 clay 15 30 31.118765
1001 clay 30 60 36.090372
1001 clay 60 100 31.251860
3. Multiple Profiles (Wide Format)
# Returns DataFrame with flattened columns: [cokey, clay_0_5, clay_5_15, ...]
df_wide = mpspline(profiles, var_name=['clay'], output_type='wide')
print(df_wide[['cokey', 'clay_0_5', 'clay_5_15', 'clay_15_30']].head())
Output:
cokey clay_0_5 clay_5_15 clay_15_30
1001 16.168706 19.762784 31.118765
1002 12.784555 14.721798 22.437913
4. Advanced Modes (1cm Resolution)
# Get high-resolution predictions at every 1cm interval
df_1cm = mpspline(profiles, var_name=['clay'], mode='1cm')
print(df_1cm[['cokey', 'var_name', 'depth', 'value']].head())
Output:
cokey var_name depth value
1001 clay 0 15.935577
1001 clay 1 15.974431
1001 clay 2 16.090996
1001 clay 3 16.285271
1001 clay 4 16.557255
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
obj |
dict or list | Required | Profile(s) with a 'horizons' key |
var_name |
str or list | None | Properties to harmonize (all numeric if None) |
target_depths |
list | GlobalSoilMap | Depth intervals as (top, bottom). Default: [(0,5), (5,15), (15,30), (30,60), (60,100), (100,200)] |
lam |
float | 0.1 | Smoothing parameter (0.01=smooth, 1.0=fit data closely) |
vlow |
float | 0.0 | Minimum constraint for values |
vhigh |
float | 1000.0 | Maximum constraint for values |
parallel |
bool | False | Use multiprocessing for multiple profiles |
batch_size |
int | 100 | Profiles per batch |
strict |
bool | False | Raise exceptions on validation errors (False = skip) |
Horizon Input Format
Required fields:
- Depth:
upperandlower(ortopandbottom) in cm - Properties: numeric fields to harmonize
Optional:
hzname: horizon name
Example:
{
'hzname': 'Ap',
'upper': 0,
'lower': 20,
'clay': 24.5,
'sand': 42.3,
}
Examples
# Custom depth intervals
result = mpspline(profile, target_depths=[(0, 10), (10, 30), (30, 60)])
# Adjust smoothing (0.01=smooth, 1.0=closer to data)
result = mpspline(profile, lam=0.01)
# Constrain values to realistic ranges
result = mpspline(profile, var_name=['clay'], vlow=0, vhigh=100)
# Parallel processing for many profiles
df = mpspline(profiles, parallel=True, batch_size=500)
# Only process specific properties
df = mpspline(profiles, var_name=['clay', 'sand'])
# Error handling: skip bad profiles or raise errors
df = mpspline(profiles, strict=False) # Skip problematic profiles
try:
df = mpspline(profiles, strict=True) # Raise on errors
except ValueError as e:
print(f"Validation error: {e}")
Troubleshooting
Horizons not ordered by depth: Horizons must be sequential with no gaps or overlaps.
# Wrong
{'upper': 0, 'lower': 30}, {'upper': 20, 'lower': 50}
# Right
{'upper': 0, 'lower': 20}, {'upper': 20, 'lower': 50}
Values outside expected ranges: Use vlow and vhigh to constrain predictions:
result = mpspline(profile, vlow=0, vhigh=100)
Processing is slow: Enable parallel processing:
df = mpspline(profiles, parallel=True, batch_size=500)
How it works
The algorithm fits a mass-preserving equal-area quadratic spline to horizon data. This converts discrete observations at varying depths to standard depth intervals while preserving the average value across each depth range.
See the algorithm documentation for details.
References
- O'Brien, L. (2025). mpspline2: Mass-Preserving Spline Functions for Soil Data. R package version 0.1.9. https://doi.org/10.32614/CRAN.package.mpspline2
- Bishop, T.F.A., McBratney, A.B., & Laslett, G.M. (1999). Modelling soil attribute depth functions with equal-area quadratic smoothing splines. Geoderma, 89(3-4), 185-208. https://doi.org/10.1016/S0016-7061(99)00003-8
- Malone, B.P., McBratney, A.B., & Minasny, B. (2009). Mapping continuous depth functions of soil carbon storage and available water capacity. Geoderma, 154(3-4), 138-152. https://doi.org/10.1016/j.geoderma.2009.10.007
License
GPL 3.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mpspline-0.2.0.tar.gz.
File metadata
- Download URL: mpspline-0.2.0.tar.gz
- Upload date:
- Size: 39.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7aae9b8199be8b052619c7c9e055375eb8af4af914ebf9b6cd08663cd2db9a12
|
|
| MD5 |
e081924f73b58d1a878c19c0bc1a1d38
|
|
| BLAKE2b-256 |
81a3ec5e3705eb0146bfcb775edaaf58bcdfaeba241fd91ef709ed1181a7fa5e
|
Provenance
The following attestation bundles were made for mpspline-0.2.0.tar.gz:
Publisher:
pypi-release.yml on brownag/py-mpspline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mpspline-0.2.0.tar.gz -
Subject digest:
7aae9b8199be8b052619c7c9e055375eb8af4af914ebf9b6cd08663cd2db9a12 - Sigstore transparency entry: 820769708
- Sigstore integration time:
-
Permalink:
brownag/py-mpspline@bf551dc2f93d7b1be5e59dfd519c6023df5cb5cb -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/brownag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-release.yml@bf551dc2f93d7b1be5e59dfd519c6023df5cb5cb -
Trigger Event:
release
-
Statement type:
File details
Details for the file mpspline-0.2.0-py3-none-any.whl.
File metadata
- Download URL: mpspline-0.2.0-py3-none-any.whl
- Upload date:
- Size: 34.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
371f450c346a57210272daf03e95e25eccf251c2adce66a4bc959e56005a0966
|
|
| MD5 |
ce6e76259f1b45d096b21ae064f4c16a
|
|
| BLAKE2b-256 |
29baac4d0f987c5037d09d7bbb7a78882b9c2fae05f2d468ef79be87ad758fb2
|
Provenance
The following attestation bundles were made for mpspline-0.2.0-py3-none-any.whl:
Publisher:
pypi-release.yml on brownag/py-mpspline
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mpspline-0.2.0-py3-none-any.whl -
Subject digest:
371f450c346a57210272daf03e95e25eccf251c2adce66a4bc959e56005a0966 - Sigstore transparency entry: 820769711
- Sigstore integration time:
-
Permalink:
brownag/py-mpspline@bf551dc2f93d7b1be5e59dfd519c6023df5cb5cb -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/brownag
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-release.yml@bf551dc2f93d7b1be5e59dfd519c6023df5cb5cb -
Trigger Event:
release
-
Statement type: