Forge
npm install @statili/forge
Turns the output of @statili/stats into facts — structured statements that follow mechanically from the numbers, and the prose to render them.
Deterministic, not generated. The same data always produces the same claims.
Install
npm install @statili/forge
Usage
import { linear } from '@statili/stats'
import { linearFacts, render } from '@statili/forge'
const result = linearFacts({}, linear({ precision: 2 }, data))
if (!result.ok) {
console.error(result.message, result.helpText)
return
}
const speak = render({ labels: { x: 'week', y: 'signups' }, units: { y: 'users' } })
for (const fact of result.facts) {
console.log(fact.kind, '→', speak(fact))
}
// trend.linear → "Each additional unit of week is associated with an increase of 7.85 users in signups…"
// fit.significance → "The slope of 7.85 is statistically significant (p = 8.7e-9, 6 degrees of freedom)…"
// fit.quality → "The model accounts for 100.0% of the variation in signups — a strong fit."
Facts
A fact separates the claim from its wording, so one claim can be spoken at several lengths, in several languages, with your own axis names:
{
kind: 'trend.linear',
claim: { direction: 'rising', slope: 7.85, intercept: 4.55 },
level: 'finding',
provenance: { method: 'linear', n: 8 },
annotations: [{ kind: 'curve', role: 'fit', method: 'linear', points: [...], domain: [1, 8] }],
}
claimholds numbers and typed qualifiers — never prose. JSON-serialisable, so it can serve as ground truth in a pipeline.levelisfinding,no-findingorcaveat. “There is no trend” is a positive statement, not an absence.provenancerecords where the claim came from, including the thresholds that produced any judgement — so you can see why a fit was called “strong”, and disagree by re-rendering.annotationsare chart-ready: fitted curves, uncertainty bands, and markers for vertices or decision boundaries.
Rendering
render is the only place wording lives. Swap it out entirely to localise.
render({ verbosity: 'terse' })(fact)
// "signups: up 7.85 per additional unit of week."
render({ verbosity: 'full' })(fact)
// "Each additional unit of week is associated with an increase of 7.85 in signups…"
Two verbosities cover the two things a chart needs: a short aria-label and a longer text alternative. Both come from the same claim, so they cannot disagree with each other or with the plot.
Generators
linearFacts, polynomialFacts, powerFacts, exponentialFacts, logarithmicFacts, multilinearFacts, logisticFacts and loessFacts — one per model, all with the same shape.
License
MIT
Modules
-
Render
render, renderAnnotation, AxisLabels, AxisUnits, RenderOptions
-
Types
ClaimMap, LinearFactOptions, LogisticFactOptions, PolynomialFactOptions, PowerFactOptions, Provenance, Annotation, ClaimOf, Fact, FactKind, FactLevel, FactResult, FactResultError, FactResultSuccess, LogarithmicFactOptions, MultilinearFactOptions, RegressionMethod
-
Regression