Skip to main content

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: upper and lower (or top and bottom) 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

License

GPL 3.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mpspline-0.2.0.tar.gz (39.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mpspline-0.2.0-py3-none-any.whl (34.1 kB view details)

Uploaded Python 3

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

Hashes for mpspline-0.2.0.tar.gz
Algorithm Hash digest
SHA256 7aae9b8199be8b052619c7c9e055375eb8af4af914ebf9b6cd08663cd2db9a12
MD5 e081924f73b58d1a878c19c0bc1a1d38
BLAKE2b-256 81a3ec5e3705eb0146bfcb775edaaf58bcdfaeba241fd91ef709ed1181a7fa5e

See more details on using hashes here.

Provenance

The following attestation bundles were made for mpspline-0.2.0.tar.gz:

Publisher: pypi-release.yml on brownag/py-mpspline

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for mpspline-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 371f450c346a57210272daf03e95e25eccf251c2adce66a4bc959e56005a0966
MD5 ce6e76259f1b45d096b21ae064f4c16a
BLAKE2b-256 29baac4d0f987c5037d09d7bbb7a78882b9c2fae05f2d468ef79be87ad758fb2

See more details on using hashes here.

Provenance

The following attestation bundles were made for mpspline-0.2.0-py3-none-any.whl:

Publisher: pypi-release.yml on brownag/py-mpspline

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page