Merge pull request #124 from QURIresearch/sparklines
sparklines (issue 70)
This commit is contained in:
commit
ffe5846bfe
|
@ -36,6 +36,15 @@ You need `yarn`.
|
||||||
|
|
||||||
TODO: fill this out based on all the different packages scripts once they cool down.
|
TODO: fill this out based on all the different packages scripts once they cool down.
|
||||||
|
|
||||||
|
## If you're on NixOS
|
||||||
|
|
||||||
|
You'll need to run a command like this in order to get `yarn build` to run, especially in `packages/squiggle-lang`.
|
||||||
|
```sh
|
||||||
|
patchelf --set-interpreter $(patchelf --print-interpreter $(which mkdir)) ./node_modules/gentype/gentype.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
See [here](https://github.com/NixOS/nixpkgs/issues/107375)
|
||||||
|
|
||||||
# Pull request protocol
|
# Pull request protocol
|
||||||
|
|
||||||
Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged.
|
Please work against `staging` branch. **Do not** work against `master`. Please do not merge without approval from some subset of Quinn, Sam, and Ozzie; they will be auto-pinged.
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
yarn2nix
|
yarn2nix
|
||||||
nodePackages.npm
|
nodePackages.npm
|
||||||
nodejs
|
nodejs
|
||||||
|
patchelf
|
||||||
(pkgs.vscode-with-extensions.override {
|
(pkgs.vscode-with-extensions.override {
|
||||||
vscode = pkgs.vscodium;
|
vscode = pkgs.vscodium;
|
||||||
vscodeExtensions = pkgs.vscode-utils.extensionsFromVscodeMarketplace [
|
vscodeExtensions = pkgs.vscode-utils.extensionsFromVscodeMarketplace [
|
||||||
|
|
33
packages/squiggle-lang/__tests__/Symbolic_test.res
Normal file
33
packages/squiggle-lang/__tests__/Symbolic_test.res
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
open Js.Array
|
||||||
|
open SymbolicDist
|
||||||
|
|
||||||
|
let makeTest = (~only=false, str, item1, item2) =>
|
||||||
|
only
|
||||||
|
? Only.test(str, () => expect(item1) -> toEqual(item2))
|
||||||
|
: test(str, () => expect(item1) -> toEqual(item2))
|
||||||
|
|
||||||
|
let pdfImage = (thePdf, inps) => map(thePdf, inps)
|
||||||
|
|
||||||
|
let parameterWiseAdditionHelper = (n1: SymbolicDistTypes.normal, n2: SymbolicDistTypes.normal) => {
|
||||||
|
let normalDistAtSumMeanConstr = Normal.add(n1, n2)
|
||||||
|
let normalDistAtSumMean: SymbolicDistTypes.normal = switch normalDistAtSumMeanConstr {
|
||||||
|
| #Normal(params) => params
|
||||||
|
}
|
||||||
|
x => Normal.pdf(x, normalDistAtSumMean)
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Normal distribution with sparklines", () => {
|
||||||
|
|
||||||
|
let normalDistAtMean5: SymbolicDistTypes.normal = {mean: 5.0, stdev: 2.0}
|
||||||
|
let normalDistAtMean10: SymbolicDistTypes.normal = {mean: 10.0, stdev: 2.0}
|
||||||
|
let range20Float = E.A.rangeFloat(0, 20) // [0.0,1.0,2.0,3.0,4.0,...19.0,]
|
||||||
|
|
||||||
|
let pdfNormalDistAtMean5 = x => Normal.pdf(x, normalDistAtMean5)
|
||||||
|
let sparklineMean5 = pdfImage(pdfNormalDistAtMean5, range20Float)
|
||||||
|
makeTest("mean=5", Sparklines.create(sparklineMean5, ()), `▁▂▃▅███▅▃▂▁▁▁▁▁▁▁▁▁▁▁`)
|
||||||
|
|
||||||
|
let sparklineMean15 = normalDistAtMean5 -> parameterWiseAdditionHelper(normalDistAtMean10) -> pdfImage(range20Float)
|
||||||
|
makeTest("parameter-wise addition of two normal distributions", Sparklines.create(sparklineMean15, ()), `▁▁▁▁▁▁▁▁▁▁▂▃▅▇███▇▅▃▂`)
|
||||||
|
})
|
|
@ -1,5 +1,4 @@
|
||||||
open Rationale.Function.Infix
|
open Rationale.Function.Infix
|
||||||
|
|
||||||
module FloatFloatMap = {
|
module FloatFloatMap = {
|
||||||
module Id = Belt.Id.MakeComparable({
|
module Id = Belt.Id.MakeComparable({
|
||||||
type t = float
|
type t = float
|
||||||
|
@ -87,6 +86,11 @@ module O = {
|
||||||
let max = compare(\">")
|
let max = compare(\">")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module O2 = {
|
||||||
|
let default = (a, b) => O.default(b, a)
|
||||||
|
let toExn = (a, b) => O.toExn(b, a)
|
||||||
|
}
|
||||||
|
|
||||||
/* Functions */
|
/* Functions */
|
||||||
module F = {
|
module F = {
|
||||||
let apply = (a, e) => a |> e
|
let apply = (a, e) => a |> e
|
||||||
|
@ -269,6 +273,8 @@ module A = {
|
||||||
))
|
))
|
||||||
|> Rationale.Result.return
|
|> Rationale.Result.return
|
||||||
}
|
}
|
||||||
|
let rangeFloat = (~step=1, start, stop) =>
|
||||||
|
Belt.Array.rangeBy(start, stop, ~step) |> fmap(Belt.Int.toFloat)
|
||||||
|
|
||||||
// This zips while taking the longest elements of each array.
|
// This zips while taking the longest elements of each array.
|
||||||
let zipMaxLength = (array1, array2) => {
|
let zipMaxLength = (array1, array2) => {
|
||||||
|
@ -322,7 +328,8 @@ module A = {
|
||||||
| r => Some(r)
|
| r => Some(r)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
let filter = (o, e) => Js.Array.filter(o, e)
|
let filter = Js.Array.filter
|
||||||
|
let joinWith = Js.Array.joinWith
|
||||||
|
|
||||||
module O = {
|
module O = {
|
||||||
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
let concatSomes = (optionals: array<option<'a>>): array<'a> =>
|
||||||
|
@ -405,6 +412,7 @@ module A = {
|
||||||
: {
|
: {
|
||||||
let _ = Js.Array.push(element, continuous)
|
let _ = Js.Array.push(element, continuous)
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -434,6 +442,11 @@ module A = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module A2 = {
|
||||||
|
let fmap = (a, b) => Array.map(b, a)
|
||||||
|
let joinWith = (a, b) => A.joinWith(b, a)
|
||||||
|
}
|
||||||
|
|
||||||
module JsArray = {
|
module JsArray = {
|
||||||
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
let concatSomes = (optionals: Js.Array.t<option<'a>>): Js.Array.t<'a> =>
|
||||||
optionals
|
optionals
|
||||||
|
|
26
packages/squiggle-lang/src/rescript/utility/Sparklines.res
Normal file
26
packages/squiggle-lang/src/rescript/utility/Sparklines.res
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Port of Sindre Sorhus' Sparkly to Rescript
|
||||||
|
// reference implementation: https://github.com/sindresorhus/sparkly
|
||||||
|
// Omitting rgb "fire" style, so no `chalk` dependency
|
||||||
|
// Omitting: NaN handling, special consideration for constant data.
|
||||||
|
|
||||||
|
let ticks = [`▁`, `▂`, `▃`, `▄`, `▅`, `▆`, `▇`, `█`]
|
||||||
|
|
||||||
|
let _ticksLength = E.A.length(ticks)
|
||||||
|
|
||||||
|
let _heightToTickIndex = (maximum: float, v: float) => {
|
||||||
|
let suggestedTickIndex = Js.Math.ceil_int(v /. maximum *. Belt.Int.toFloat(_ticksLength)) - 1
|
||||||
|
max(suggestedTickIndex, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
let create = (relativeHeights: array<float>, ~maximum=?, ()) => {
|
||||||
|
if E.A.length(relativeHeights) === 0 {
|
||||||
|
""
|
||||||
|
} else {
|
||||||
|
let maximum = maximum->E.O2.default(E.A.max(relativeHeights)->E.O2.toExn(""))
|
||||||
|
|
||||||
|
relativeHeights
|
||||||
|
->E.A2.fmap(_heightToTickIndex(maximum))
|
||||||
|
->E.A2.fmap(r => E.A.get(ticks, r)->E.O2.toExn(""))
|
||||||
|
->E.A2.joinWith("")
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user