open DistPlusPlotReducer; let plotBlue = `hex("1860ad"); let showAsForm = (distPlus: DistTypes.distPlus) => {
E.O.default("")} />
; }; let showFloat = (~precision=3, number) => ; let table = (distPlus, x) => {
{"X Point" |> ReasonReact.string} {"Discrete Value" |> ReasonReact.string} {"Continuous Value" |> ReasonReact.string} {"Y Integral to Point" |> ReasonReact.string} {"Y Integral Total" |> ReasonReact.string}
{x |> E.Float.toString |> ReasonReact.string} {distPlus |> DistPlus.T.xToY(x) |> DistTypes.MixedPoint.toDiscreteValue |> Js.Float.toPrecisionWithPrecision(_, ~digits=7) |> ReasonReact.string} {distPlus |> DistPlus.T.xToY(x) |> DistTypes.MixedPoint.toContinuousValue |> Js.Float.toPrecisionWithPrecision(_, ~digits=7) |> ReasonReact.string} {distPlus |> DistPlus.T.Integral.xToY(x) |> E.Float.with2DigitsPrecision |> ReasonReact.string} {distPlus |> DistPlus.T.Integral.sum |> E.Float.with2DigitsPrecision |> ReasonReact.string}
{"Continuous Total" |> ReasonReact.string} {"Discrete Total" |> ReasonReact.string}
{distPlus |> DistPlus.T.toContinuous |> E.O.fmap( Continuous.T.Integral.sum ) |> E.O.fmap(E.Float.with2DigitsPrecision) |> E.O.default("") |> ReasonReact.string} {distPlus |> DistPlus.T.toDiscrete |> E.O.fmap(Discrete.T.Integral.sum) |> E.O.fmap(E.Float.with2DigitsPrecision) |> E.O.default("") |> ReasonReact.string}
; }; let percentiles = distPlus => {
{"1" |> ReasonReact.string} {"5" |> ReasonReact.string} {"25" |> ReasonReact.string} {"50" |> ReasonReact.string} {"75" |> ReasonReact.string} {"95" |> ReasonReact.string} {"99" |> ReasonReact.string} {"99.999" |> ReasonReact.string}
{distPlus |> DistPlus.T.Integral.yToX(0.01) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.05) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.25) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.5) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.75) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.95) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.99) |> showFloat} {distPlus |> DistPlus.T.Integral.yToX(0.99999) |> showFloat}
{"mean" |> ReasonReact.string} {"standard deviation" |> ReasonReact.string} {"variance" |> ReasonReact.string}
{distPlus |> DistPlus.T.mean |> showFloat} {distPlus |> DistPlus.T.variance |> (r => r ** 0.5) |> showFloat} {distPlus |> DistPlus.T.variance |> showFloat}
; }; let adjustBoth = discreteProbabilityMassFraction => { let yMaxDiscreteDomainFactor = discreteProbabilityMassFraction; let yMaxContinuousDomainFactor = 1.0 -. discreteProbabilityMassFraction; // use the bigger proportion, such that whichever is the bigger proportion, the yMax is 1. let yMax = (yMaxDiscreteDomainFactor > 0.5 ? yMaxDiscreteDomainFactor : yMaxContinuousDomainFactor); ( yMax /. yMaxDiscreteDomainFactor, yMax /. yMaxContinuousDomainFactor, ); }; module DistPlusChart = { [@react.component] let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => { open DistPlus; let discrete = distPlus |> T.toDiscrete |> E.O.fmap(Discrete.getShape); let continuous = distPlus |> T.toContinuous |> E.O.fmap(Continuous.getShape); let range = T.xTotalRange(distPlus); // // We subtract a bit from the range to make sure that it fits. Maybe this should be done in d3 instead. // let minX = // switch ( // distPlus // |> DistPlus.T.Integral.yToX(0.0001), // range, // ) { // | (min, Some(range)) => Some(min -. range *. 0.001) // | _ => None // }; let minX = { distPlus |> DistPlus.T.Integral.yToX(0.00001); }; let maxX = { distPlus |> DistPlus.T.Integral.yToX(0.99999); }; let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; let discreteProbabilityMassFraction = distPlus |> DistPlus.T.toDiscreteProbabilityMassFraction; let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) = adjustBoth(discreteProbabilityMassFraction); ; }; }; module IntegralChart = { [@react.component] let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => { let integral = distPlus.integralCache; let continuous = integral |> Continuous.toLinear |> E.O.fmap(Continuous.getShape); let minX = { distPlus |> DistPlus.T.Integral.yToX(0.00001); }; let maxX = { distPlus |> DistPlus.T.Integral.yToX(0.99999); }; let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson; ; }; }; module Chart = { [@react.component] let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => { let chart = React.useMemo2( () => { config.isCumulative ? : }, (distPlus, config), );
chart
; }; }; let button = "bg-gray-300 hover:bg-gray-500 text-grey-darkest text-xs px-4 py-1"; [@react.component] let make = (~distPlus: DistTypes.distPlus) => { let (x, setX) = React.useState(() => 0.); let (state, dispatch) = React.useReducer(DistPlusPlotReducer.reducer, DistPlusPlotReducer.init);
{state.distributions |> E.L.fmapi((index, config) =>
{setX(_ => r)}} />
{index != 0 ? : ReasonReact.null}
) |> E.L.toArray |> ReasonReact.array}
{state.showParams ? showAsForm(distPlus) : ReasonReact.null} {state.showStats ? table(distPlus, x) : ReasonReact.null} {state.showPercentiles ? percentiles(distPlus) : ReasonReact.null}
; };