Implement generic sparklines with tests
This commit is contained in:
parent
51f2fce2c4
commit
53f4e56529
|
@ -0,0 +1,35 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
let env: DistributionOperation.env = {
|
||||||
|
sampleCount: 100,
|
||||||
|
xyPointLength: 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalDist: GenericDist_Types.genericDist = Symbolic(#Normal({mean: 5.0, stdev: 2.0}))
|
||||||
|
let uniformDist: GenericDist_Types.genericDist = Symbolic(#Uniform({low: 9.0, high: 10.0}))
|
||||||
|
let betaDist: GenericDist_Types.genericDist = Symbolic(#Beta({alpha: 2.0, beta: 5.0}))
|
||||||
|
let lognormalDist: GenericDist_Types.genericDist = Symbolic(#Lognormal({mu: 0.0, sigma: 1.0}))
|
||||||
|
let cauchyDist: GenericDist_Types.genericDist = Symbolic(#Cauchy({local: 1.0, scale: 1.0}))
|
||||||
|
let triangularDist: GenericDist_Types.genericDist = Symbolic(#Triangular({low: 1.0, medium: 2.0, high: 3.0}))
|
||||||
|
let exponentialDist: GenericDist_Types.genericDist = Symbolic(#Exponential({rate: 2.0}))
|
||||||
|
|
||||||
|
let runTest = (name: string, dist : GenericDist_Types.genericDist, expected: string) => {
|
||||||
|
test(name, () => {
|
||||||
|
let result = GenericDist.toSparkline(~xyPointLength=100, ~sampleCount=100, ~buckets=20, dist)
|
||||||
|
switch result {
|
||||||
|
| Ok(sparkline) => expect(sparkline)->toEqual(expected)
|
||||||
|
| Error(err) => expect("Error")->toEqual(expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("sparkline of generic distribution", () => {
|
||||||
|
runTest("normal", normalDist, `▁▁▁▁▂▃▄▆▇██▇▆▄▃▂▁▁▁`)
|
||||||
|
runTest("uniform", uniformDist, `████████████████████`)
|
||||||
|
runTest("beta", uniformDist, `████████████████████`)
|
||||||
|
runTest("lognormal", lognormalDist, `█▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`)
|
||||||
|
runTest("cauchy", cauchyDist, `▁▁▁▁▁▁▁▁▁██▁▁▁▁▁▁▁▁▁`)
|
||||||
|
runTest("triangular", triangularDist, `▁▂▃▄▄▅▆▇████▇▆▅▄▄▃▂▁`)
|
||||||
|
runTest("exponential", exponentialDist, `█▆▄▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁`)
|
||||||
|
})
|
|
@ -49,7 +49,7 @@ let toFloatOperation = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Todo: If it's a pointSet, but the xyPointLenght is different from what it has, it should change.
|
//Todo: If it's a pointSet, but the xyPointLength is different from what it has, it should change.
|
||||||
// This is tricky because the case of discrete distributions.
|
// This is tricky because the case of discrete distributions.
|
||||||
// Also, change the outputXYPoints/pointSetDistLength details
|
// Also, change the outputXYPoints/pointSetDistLength details
|
||||||
let toPointSet = (~xyPointLength, ~sampleCount, t): result<PointSetTypes.pointSetDist, error> => {
|
let toPointSet = (~xyPointLength, ~sampleCount, t): result<PointSetTypes.pointSetDist, error> => {
|
||||||
|
@ -75,6 +75,9 @@ let toPointSet = (~xyPointLength, ~sampleCount, t): result<PointSetTypes.pointSe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let toSparkline = (~xyPointLength: int, ~sampleCount: int, ~buckets: int = 20, t: t) : result<string, error> =>
|
||||||
|
toPointSet(~xyPointLength, ~sampleCount, t) -> E.R2.fmap(PointSetDist.toSparkline(buckets))
|
||||||
|
|
||||||
module Truncate = {
|
module Truncate = {
|
||||||
let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option<t> =>
|
let trySymbolicSimplification = (leftCutoff, rightCutoff, t: t): option<t> =>
|
||||||
switch (leftCutoff, rightCutoff, t) {
|
switch (leftCutoff, rightCutoff, t) {
|
||||||
|
|
|
@ -24,6 +24,12 @@ let toPointSet: (
|
||||||
~sampleCount: int,
|
~sampleCount: int,
|
||||||
t,
|
t,
|
||||||
) => result<PointSetTypes.pointSetDist, error>
|
) => result<PointSetTypes.pointSetDist, error>
|
||||||
|
let toSparkline: (
|
||||||
|
~xyPointLength: int,
|
||||||
|
~sampleCount: int,
|
||||||
|
~buckets: int=?,
|
||||||
|
t,
|
||||||
|
) => result<string, error>
|
||||||
|
|
||||||
let truncate: (
|
let truncate: (
|
||||||
t,
|
t,
|
||||||
|
|
|
@ -168,6 +168,22 @@ let pdf = (f: float, t: t) => {
|
||||||
let inv = T.Integral.yToX
|
let inv = T.Integral.yToX
|
||||||
let cdf = T.Integral.xToY
|
let cdf = T.Integral.xToY
|
||||||
|
|
||||||
|
let diff = (arr: array<float>): array<float> =>
|
||||||
|
Belt.Array.zipBy(arr, Belt.Array.sliceToEnd(arr, 1), (left, right) => right -. left)
|
||||||
|
|
||||||
|
let rec rangeByFloat = (start : float, end: float, step: float) =>
|
||||||
|
start > end ?
|
||||||
|
[]
|
||||||
|
: Belt.Array.concat([start], rangeByFloat(start +. step, end, step))
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let toSparkline = (buckets: int, t: t ): string => {
|
||||||
|
let size : float = T.maxX(t) -. T.minX(t)
|
||||||
|
let stepSize = size /. Belt.Int.toFloat(buckets)
|
||||||
|
let cdf = rangeByFloat(T.minX(t), T.maxX(t), stepSize) -> Belt.Array.map(val => cdf(val,t))
|
||||||
|
Sparklines.create(diff(cdf), ())
|
||||||
|
}
|
||||||
|
|
||||||
let doN = (n, fn) => {
|
let doN = (n, fn) => {
|
||||||
let items = Belt.Array.make(n, 0.0)
|
let items = Belt.Array.make(n, 0.0)
|
||||||
for x in 0 to n - 1 {
|
for x in 0 to n - 1 {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user