Skip to main content

ODR Bootstrap

Tests codecov PyPI Python 3.12+ License: MIT

Orthogonal Distance Regression with Bootstrap Resampling for SIMS Calibration

A Python package for robust calibration curve fitting with proper uncertainty quantification in both x and y measurements.

Overview

What is ODR Bootstrap?

When fitting calibration curves to scientific data, measurement errors exist in both the independent variable (x, e.g., concentration) and dependent variable (y, e.g., ion intensity). Ordinary least squares regression assumes errors only in y, leading to biased fits.

Orthogonal Distance Regression (ODR) properly accounts for uncertainties in both x and y. Bootstrap resampling estimates confidence intervals by repeatedly refitting the model to random subsamples of the calibration data.

This package combines these techniques for publication-ready uncertainty quantification in SIMS (Secondary Ion Mass Spectrometry) calibration analysis.

Features

✅ NumPy-style documentation for all functions
✅ 22 comprehensive unit tests (100% pass rate)
✅ Runnable example workflow with synthetic data
✅ Compatible with scipy 1.15+ (deprecated API updates)
✅ Zero-intercept fits with proper parameter handling
✅ Publication-ready calibration plots

Installation

uv pip install odr-bootstrap

With pip

pip install odr-bootstrap

From source

git clone https://github.com/whtowbin/odr-bootstrap.git
cd odr-bootstrap
uv sync
# or
pip install -e .

Documentation

Full documentation is available at Read the Docs.

For quick reference, see:

Quick Start

import numpy as np import matplotlib.pyplot as plt from odr_bootstrap import ODR_Bootstrap, plot_regression

Prepare calibration data

x_standards = np.array([0.1, 0.5, 1.0, 2.0, 5.0]) # Concentrations y_intensity = np.array([45, 200, 350, 700, 1450]) # Ion counts x_uncertainty = np.array([0.01, 0.05, 0.1, 0.2, 0.5]) # Measurement errors in x y_uncertainty = np.array([5, 20, 35, 60, 120]) # Measurement errors in y

Run ODR bootstrap with 2000 resamples

confidence_data, best_fit_params, points, all_params, subsamples = ODR_Bootstrap( x=x_standards, y=y_intensity, x_err=x_uncertainty, y_err=y_uncertainty, resample_draws=2000, InterceptFit=True, InitialGuess=[250, 10], Confidence_Bound=0.95, LineMax=6, )

Plot the result

fig, ax = plt.subplots(figsize=(8, 5)) plot_regression(confidence_data, datapoints=points, ax=ax, ecolor='lightblue', line_color='darkblue', linewidth=2) ax.set_xlabel('Concentration (ppm)') ax.set_ylabel('Ion Intensity (counts)') ax.set_title('SIMS Calibration Curve with 95% Bootstrap CI') plt.tight_layout() plt.savefig('calibration_curve.png', dpi=150) plt.show()

Access results

print(f"Slope: {best_fit_params[0]:.2f}") print(f"Intercept: {best_fit_params[1]:.2f}")


### Plotting Calibration Estimate Distributions

```python
from odr_bootstrap import plot_Calibration_Estimates
import numpy as np

# Extract bootstrap parameter distributions
all_slopes = np.array([p[0] for p in all_params])
all_intercepts = np.array([p[1] for p in all_params])

# Create synthetic measurement ensemble (for visualization)
fit_params = np.array([[all_slopes.mean(), all_intercepts.mean()]] * 5)
fit_params += np.random.normal(0, [all_slopes.std(), all_intercepts.std()], (5, 2))
fit_error = np.array([[all_slopes.std(), all_intercepts.std()]] * 5)

# Generate plot
fig = plot_Calibration_Estimates(fit_params, fit_error,
                               Title="Calibration Slope & Intercept Distributions")
plt.savefig('calibration_estimates.png', dpi=150)
plt.show()

Module Functions

Core Fitting

  • ODR_Linear(x, y, x_err, y_err, intercept=False, InitialGuess=[100, 1])
    Single orthogonal distance regression fit with optional y-intercept. Returns: (fitted_params, param_uncertainties)

  • ODR_Linear_Test(x, y, x_err, y_err, ...)
    ODR fit returning full scipy.odr output object for diagnostics.

  • Bootstrap_fit(x, y, x_err, y_err, resample_draws, ...)
    Resample data N times and fit ODR model to each resample. Returns: (all_fit_params, resampled_data)

Confidence Intervals

  • Eval_Conf(Fit_Param, Confidence_Bound=0.95, LineMax=200, ...)
    Compute confidence intervals from bootstrap parameter distributions. Returns: DataFrame with confidence bounds indexed by x-values.

  • ODR_Bootstrap(...)
    Convenience wrapper combining Bootstrap_fit + Eval_Conf in one call.

Statistics

  • gauss_agv_err(concentrations, errors, ...)
    Aggregate multiple normal distributions into single KDE estimate. Returns: (distribution_dict, statistics_dict)

Plotting

  • plot_regression(confidence_df, datapoints=None, ax=None, ...)
    Plot best-fit line with shaded confidence band.

  • plot_datapoints(data, bounds, ax=None, ...)
    Plot probability density curve with summary statistics.

  • plot_Calibration_Estimates(fit_params, fit_error, Title=...)
    Side-by-side slope and intercept distribution plots.

Testing

Run the comprehensive test suite:

python -m unittest tests/test_odr_bootstrap.py -v

Or with pytest:

pytest tests/ -v

All 22 tests should pass.

Example Workflow

See examples/example.py for a complete working example:

cd examples
python example.py

This generates:

  • calibration_curve.png - Fitted line with confidence band
  • calibration_estimates.png - Bootstrap parameter distributions

Recent Updates (April 2025)

  • ✅ Fixed zero-intercept ODR fits with proper scipy.odr parameter wrapping
  • ✅ Updated deprecated np.trapz API to np.trapezoid (scipy 1.15+ compatible)
  • ✅ Added comprehensive NumPy-style docstrings to all functions
  • ✅ Created 22 unit tests with 100% pass rate
  • ✅ Generated runnable example workflow

API Reference

Full documentation is available in function docstrings:

from odr_bootstrap import ODR_Bootstrap
help(ODR_Bootstrap)

Requirements

  • Python >= 3.12
  • numpy >= 2.2.4
  • scipy >= 1.15.2
  • pandas >= 2.2.3
  • matplotlib >= 3.10.1

License

MIT License - See LICENSE file for details.

Citation

If you use this package in research, please cite:

@software{towbin2025odr,
  title={ODR Bootstrap: Orthogonal Distance Regression with Bootstrap Resampling},
  author={Towbin, Henry},
  year={2025},
  url={https://github.com/whtowbin/odr-bootstrap}
}

Contributing

Contributions welcome! Please open an issue or submit a pull request.

Acknowledgments

Developed at Caltech for SIMS calibration analysis workflows.


Status: Beta (0.1.0) | Last Updated: April 2025

Metadata

Release files for odr-bootstrap 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for odr-bootstrap 0.1.0
File Size Uploaded
odr_bootstrap-0.1.0.tar.gz 26.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for odr-bootstrap 0.1.0
File Interpreter ABI Platform
odr_bootstrap-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.8 kB

Release files / odr_bootstrap-0.1.0.tar.gz

Download URL odr_bootstrap-0.1.0.tar.gz
Size 26.9 kB
Tags Source
SHA-256 checksum
How to use checksums
7be3e1827865efda87aabbfaf7c4f9f5b89ccbe5f902405852cb387ea05c9f5a
BLAKE2b-256 checksum
How to use checksums
1007c6c2b599a44df6fbd518cf4408842fc94ed136c675dfc76c7ecd498057d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / odr_bootstrap-0.1.0-py3-none-any.whl

Download URL odr_bootstrap-0.1.0-py3-none-any.whl
Size 10.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
808068f56042abffb829e3121dfa72089c00b60981f21f09696c08eca06cb62f
BLAKE2b-256 checksum
How to use checksums
b849d3f40f802f3345e01cdcea95f0722947cd4e85bb1c465f0aafaf87865c54
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

2.1.0

2 release files

2.0.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page