Interpolation plugin for Polars
Project description
interpolars
interpolars is a small Polars plugin that does N-dimensional linear interpolation from a
source “grid” (your DataFrame) onto an explicit target DataFrame.
It supports:
- 1D/2D/3D/... multilinear interpolation
- Multiple value columns in one call
- Target passthrough columns (e.g. labels/metadata)
- Grouped interpolation over “extra” coordinate dims (e.g. group by
timeand interpolate overlatitude/longitudefor each time slice) - Non-float coordinate dtypes such as Date and Duration (they are cast internally for interpolation math; group keys preserve dtype in output)
Installation
This repo is built with maturin and managed with uv.
- As a local editable/dev install (recommended for hacking on it):
cd /path/to/interpolars
uv sync --dev
- Run tests:
cd /path/to/interpolars
uv run pytest
Notes:
- Python:
>= 3.12(seepyproject.toml) - Polars: pinned to
polars==1.37.1
The API: interpolate_nd
The only public function is interpolate_nd, which returns a Polars expression (pl.Expr).
from interpolars import interpolate_nd
expr = interpolate_nd(
expr_cols_or_exprs=["x", "y"], # source coordinate columns/exprs
value_cols_or_exprs=["value_a", "value_b"], # source value columns/exprs
interp_target=target_df, # a *DataFrame* with target coordinates (+ metadata)
)
You typically use it inside LazyFrame.select:
import polars as pl
from interpolars import interpolate_nd
out = (
source_df.lazy()
.select(interpolate_nd(["x", "y"], ["value"], target_df))
.collect()
)
Output shape and how to consume it
interpolate_nd(...) produces a single struct column named "interpolated".
That struct contains, in order:
- all columns from
interp_target(including metadata likelabel) - any “extra/group” coordinate dims from the source (see next section)
- all interpolated value fields
To “flatten” the result into normal columns, use unnest:
flat = (
source_df.lazy()
.select(interpolate_nd(["x", "y"], ["value"], target_df))
.unnest("interpolated")
.collect()
)
Or access fields directly:
only_value = (
source_df.lazy()
.select(interpolate_nd(["x"], ["value"], target_df).struct.field("value").alias("value"))
.collect()
)
Grouped interpolation over extra coordinate dims (e.g. time slices)
If the source coordinate columns include fields that do not exist in interp_target,
those fields are treated as grouping dimensions.
Example:
- source coords:
["latitude", "longitude", "time"] - target df columns:
["latitude", "longitude", "label"] - values:
["2m_temp", "precipitation"]
Then time is a group key:
- The source rows are grouped by unique
time - Interpolation runs over (
latitude,longitude) within each time group - Results are concatenated, producing
len(target_df) * n_timesrows
import polars as pl
from interpolars import interpolate_nd
target = pl.DataFrame(
{
"latitude": [0.25, 0.75],
"longitude": [0.50, 0.25],
"label": ["a", "b"],
}
)
out = (
source_df.lazy()
.select(
interpolate_nd(
["latitude", "longitude", "time"],
["2m_temp", "precipitation"],
target,
)
)
.unnest("interpolated")
.collect()
)
Output order is deterministic:
- target rows are repeated per group
- groups are ordered by ascending group key (e.g. ascending
time)
Date and Duration coordinates
Coordinate columns can be pl.Date, pl.Datetime, and pl.Duration (and other numeric-like
dtypes). The plugin will cast coordinates internally for interpolation computations.
Example (Date as an interpolation axis):
from datetime import date
import polars as pl
from interpolars import interpolate_nd
source = pl.DataFrame(
{
"d": pl.Series("d", [date(2020, 1, 1), date(2020, 1, 3)], dtype=pl.Date),
"value": [0.0, 2.0],
}
)
target = pl.DataFrame(
{
"d": pl.Series("d", [date(2020, 1, 2)], dtype=pl.Date),
"label": ["mid"],
}
)
out = (
source.lazy()
.select(interpolate_nd(["d"], ["value"], target))
.unnest("interpolated")
.collect()
)
Example (Duration as an interpolation axis):
import polars as pl
from interpolars import interpolate_nd
source = pl.DataFrame(
{
"dt": pl.Series("dt", [0, 10_000], dtype=pl.Duration("ms")),
"value": [0.0, 10.0],
}
)
target = pl.DataFrame(
{
"dt": pl.Series("dt", [5_000], dtype=pl.Duration("ms")),
"label": ["half"],
}
)
out = (
source.lazy()
.select(interpolate_nd(["dt"], ["value"], target))
.unnest("interpolated")
.collect()
)
Important constraints / behavior
- No nulls: coordinate or value inputs containing nulls will error.
- Source must be a full cartesian grid (per group) for the interpolation dimensions: every “corner” required for multilinear interpolation must exist, otherwise you’ll get an error.
- Out-of-bounds targets clamp: if a target coordinate is below the min axis value it clamps to the min; above max clamps to the max.
- Duplicate names: value field names cannot collide with
interp_targetcolumns (and group fields cannot collide either); collisions error.
Project layout
src/interpolars/__init__.py: Python API wrapper (registers the Polars plugin function)src/expressions.rs: the Polars expression implementation (Rust)tests/: pytest suite with examples (including grouped + Date/Duration coverage)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
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 interpolars-0.1.0-cp39-abi3-manylinux_2_24_x86_64.whl.
File metadata
- Download URL: interpolars-0.1.0-cp39-abi3-manylinux_2_24_x86_64.whl
- Upload date:
- Size: 6.8 MB
- Tags: CPython 3.9+, manylinux: glibc 2.24+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Linux Mint","version":"22","id":"wilma","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed04314b9dafec57fc656670c42dd8fd98ddd90b112144c70e2358eadd79e0ea
|
|
| MD5 |
dfa990a00635f6f4f7d3e6a38d5ed7be
|
|
| BLAKE2b-256 |
a72c968ad0fd3f49ffe3f0011f264c739c0988558d4f15241515970aa685287c
|