Skip to content

Commit

Permalink
Merge pull request #444 from Open-Earth-Foundation/on-1592
Browse files Browse the repository at this point in the history
feat: function for estimating value from a series
  • Loading branch information
evanp authored Apr 16, 2024
2 parents 7e0da34 + 5e1619e commit 2f67201
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 0 deletions.
46 changes: 46 additions & 0 deletions app/src/util/series.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
export function estimate(series: { year: number, value: number }[], year: number): number | null {

// if it's in the series, just return the value

const exact = series.find(e => e.year === year);
if (exact) {
return exact.value;
}

// we need at least two points to interpolate or extrapolate

if (series.length < 2) {
return null;
}

if (year < series[0].year) { // extrapolate backwards
let first = series[0]
let next = series.find(e => e.year - first.year >= first.year - year)
if (!next) {
return null
}
let rate = (next.value - first.value) / (next.year - first.year);
let value = first.value - rate * (first.year - year)
return value
} else if (year > series[series.length - 1].year) { // extrapolate forwards
let last = series[series.length - 1]
let prev = series.findLast(e => last.year - e.year >= year - last.year)
if (!prev) {
return null
}
let rate = (last.value - prev.value) / (last.year - prev.year);
let value = last.value + rate * (year - last.year)
return value
} else { // interpolate
let prev = series.findLast(e => e.year < year)
let next = series.find(e => e.year > year)
if (!prev || !next) {
return null
}
let rate = (next.value - prev.value) / (next.year - prev.year);
let value = prev.value + rate * (year - prev.year)
return value
}

return null;
}
60 changes: 60 additions & 0 deletions app/tests/series.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { describe, it } from "node:test"
import assert from "node:assert/strict"
import { estimate } from "@/util/series"

describe("Series", () => {
let series0 = [
{ year: 2000, value: 100 }
];

let series = [
{ year: 2000, value: 100 },
{ year: 2010, value: 200 },
{ year: 2020, value: 400 }
];

it("should return exact value for small series on match", () => {
let result = estimate(series0, 2000);
assert.strictEqual(result, 100);
})

it("should return null for small series on no match", () => {
let result = estimate(series0, 2001);
assert.strictEqual(result, null);
})

it("should return exact value", () => {
let result = estimate(series, 2010);
assert.strictEqual(result, 200);
})

it("should return interpolated value at low rate", () => {
let result = estimate(series, 2005);
assert.strictEqual(result, 150);
})

it("should return interpolated value at high rate", () => {
let result = estimate(series, 2015);
assert.strictEqual(result, 300);
})

it("should return extrapolated value at low rate", () => {
let result = estimate(series, 1995);
assert.strictEqual(result, 50);
})

it("should return extrapolated value at high rate", () => {
let result = estimate(series, 2025);
assert.strictEqual(result, 500);
})

it("should return null if below safe extrapolation range", () => {
let result = estimate(series, 1979);
assert.strictEqual(result, null);
})

it("should return null if above safe extrapolation range", () => {
let result = estimate(series, 2041);
assert.strictEqual(result, null);
})
})

0 comments on commit 2f67201

Please sign in to comment.