Added ability to add-remove dists
This commit is contained in:
parent
bdeb53a6c4
commit
f45b4b763a
|
@ -1,15 +1,4 @@
|
||||||
type state = {
|
open DistPlusPlotReducer;
|
||||||
log: bool,
|
|
||||||
showStats: bool,
|
|
||||||
showParams: bool,
|
|
||||||
height: int,
|
|
||||||
};
|
|
||||||
|
|
||||||
type action =
|
|
||||||
| CHANGE_LOG
|
|
||||||
| CHANGE_SHOW_STATS
|
|
||||||
| CHANGE_SHOW_PARAMS
|
|
||||||
| CHANGE_HEIGHT(int);
|
|
||||||
|
|
||||||
let showAsForm = (distPlus: DistTypes.distPlus) => {
|
let showAsForm = (distPlus: DistTypes.distPlus) => {
|
||||||
<div>
|
<div>
|
||||||
|
@ -146,7 +135,7 @@ let adjustBoth = discreteProbabilityMass => {
|
||||||
|
|
||||||
module DistPlusChart = {
|
module DistPlusChart = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~distPlus: DistTypes.distPlus, ~state: state, ~onHover) => {
|
let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
||||||
open Distributions.DistPlus;
|
open Distributions.DistPlus;
|
||||||
let discrete = distPlus |> T.toScaledDiscrete;
|
let discrete = distPlus |> T.toScaledDiscrete;
|
||||||
let continuous =
|
let continuous =
|
||||||
|
@ -166,27 +155,25 @@ module DistPlusChart = {
|
||||||
distPlus |> Distributions.DistPlus.T.toDiscreteProbabilityMass;
|
distPlus |> Distributions.DistPlus.T.toDiscreteProbabilityMass;
|
||||||
let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) =
|
let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) =
|
||||||
adjustBoth(toDiscreteProbabilityMass);
|
adjustBoth(toDiscreteProbabilityMass);
|
||||||
<div className=Css.(style([minHeight(`px(state.height))]))>
|
|
||||||
<DistributionPlot
|
<DistributionPlot
|
||||||
scale={state.log ? "log" : "linear"}
|
scale={config.log ? "log" : "linear"}
|
||||||
|
height={DistPlusPlotReducer.heightToPix(config.height)}
|
||||||
minX
|
minX
|
||||||
maxX
|
maxX
|
||||||
yMaxDiscreteDomainFactor
|
yMaxDiscreteDomainFactor
|
||||||
yMaxContinuousDomainFactor
|
yMaxContinuousDomainFactor
|
||||||
height={state.height}
|
|
||||||
?discrete
|
?discrete
|
||||||
?continuous
|
?continuous
|
||||||
color={`hex("5f6b7e")}
|
color={`hex("5f6b7e")}
|
||||||
onHover
|
onHover
|
||||||
timeScale
|
timeScale
|
||||||
/>
|
/>;
|
||||||
</div>;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module IntegralChart = {
|
module IntegralChart = {
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~distPlus: DistTypes.distPlus, ~onHover) => {
|
let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
||||||
open Distributions.DistPlus;
|
open Distributions.DistPlus;
|
||||||
let integral =
|
let integral =
|
||||||
Distributions.DistPlus.T.toShape(distPlus)
|
Distributions.DistPlus.T.toShape(distPlus)
|
||||||
|
@ -204,9 +191,10 @@ module IntegralChart = {
|
||||||
let maxX = integral |> Distributions.Continuous.T.maxX;
|
let maxX = integral |> Distributions.Continuous.T.maxX;
|
||||||
let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson;
|
let timeScale = distPlus.unit |> DistTypes.DistributionUnit.toJson;
|
||||||
<DistributionPlot
|
<DistributionPlot
|
||||||
|
scale={config.log ? "log" : "linear"}
|
||||||
|
height={DistPlusPlotReducer.heightToPix(config.height)}
|
||||||
minX
|
minX
|
||||||
maxX
|
maxX
|
||||||
height=80
|
|
||||||
?continuous
|
?continuous
|
||||||
color={`hex("5f6b7e")}
|
color={`hex("5f6b7e")}
|
||||||
timeScale
|
timeScale
|
||||||
|
@ -215,64 +203,94 @@ module IntegralChart = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module Chart = {
|
||||||
|
[@react.component]
|
||||||
|
let make = (~distPlus: DistTypes.distPlus, ~config: chartConfig, ~onHover) => {
|
||||||
|
let chart =
|
||||||
|
React.useMemo2(
|
||||||
|
() => {
|
||||||
|
config.isCumulative
|
||||||
|
? <IntegralChart distPlus config onHover />
|
||||||
|
: <DistPlusChart distPlus config onHover />
|
||||||
|
},
|
||||||
|
(distPlus, config),
|
||||||
|
);
|
||||||
|
<div
|
||||||
|
className=Css.(
|
||||||
|
style([
|
||||||
|
minHeight(`px(DistPlusPlotReducer.heightToPix(config.height))),
|
||||||
|
])
|
||||||
|
)>
|
||||||
|
chart
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
let button = "bg-gray-300 hover:bg-gray-500 text-grey-darkest text-xs px-4 py-1";
|
let button = "bg-gray-300 hover:bg-gray-500 text-grey-darkest text-xs px-4 py-1";
|
||||||
|
|
||||||
[@react.component]
|
[@react.component]
|
||||||
let make = (~distPlus: DistTypes.distPlus) => {
|
let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
let (x, setX) = React.useState(() => 0.);
|
let (x, setX) = React.useState(() => 0.);
|
||||||
let (state, dispatch) =
|
let (state, dispatch) =
|
||||||
React.useReducer(
|
React.useReducer(DistPlusPlotReducer.reducer, DistPlusPlotReducer.init);
|
||||||
(state: state, action: action) =>
|
|
||||||
switch (action) {
|
|
||||||
| CHANGE_LOG => {...state, log: !state.log}
|
|
||||||
| CHANGE_HEIGHT(height) => {...state, height}
|
|
||||||
| CHANGE_SHOW_STATS => {...state, showStats: !state.showStats}
|
|
||||||
| CHANGE_SHOW_PARAMS => {...state, showParams: !state.showParams}
|
|
||||||
},
|
|
||||||
{log: false, height: 80, showStats: false, showParams: false},
|
|
||||||
);
|
|
||||||
let chart =
|
|
||||||
React.useMemo2(
|
|
||||||
() => {<DistPlusChart distPlus state onHover={r => {setX(_ => r)}} />},
|
|
||||||
(distPlus, state),
|
|
||||||
);
|
|
||||||
let chart2 =
|
|
||||||
React.useMemo1(
|
|
||||||
() => {<IntegralChart distPlus onHover={r => {setX(_ => r)}} />},
|
|
||||||
[|distPlus|],
|
|
||||||
);
|
|
||||||
<div>
|
<div>
|
||||||
chart
|
{state.distributions
|
||||||
chart2
|
|> E.L.fmapi((index, config) =>
|
||||||
<div className="inline-flex opacity-50 hover:opacity-100">
|
<div className="flex">
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_LOG)}>
|
<div className="w-4/5">
|
||||||
{(state.log ? "x-Linear" : "x-Log") |> ReasonReact.string}
|
<Chart distPlus config onHover={r => {setX(_ => r)}} />
|
||||||
|
</div>
|
||||||
|
<div className="w-1/5">
|
||||||
|
<div className="opacity-50 hover:opacity-100">
|
||||||
|
<button
|
||||||
|
className=button
|
||||||
|
onClick={_ => dispatch(CHANGE_LOG(index))}>
|
||||||
|
{(state.log ? "log" : "linear") |> ReasonReact.string}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className=button
|
||||||
|
onClick={_ =>
|
||||||
|
dispatch(
|
||||||
|
CHANGE_IS_CUMULATIVE(index, !config.isCumulative),
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
{(config.isCumulative ? "cdf" : "pdf") |> ReasonReact.string}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className=button
|
||||||
|
onClick={_ => dispatch(HEIGHT_INCREMENT(index))}>
|
||||||
|
{"Expand" |> ReasonReact.string}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className=button
|
||||||
|
onClick={_ => dispatch(HEIGHT_DECREMENT(index))}>
|
||||||
|
{"Compress" |> ReasonReact.string}
|
||||||
|
</button>
|
||||||
|
{index != 0
|
||||||
|
? <button
|
||||||
|
className=button
|
||||||
|
onClick={_ => dispatch(REMOVE_DIST(index))}>
|
||||||
|
{"Remove" |> ReasonReact.string}
|
||||||
|
</button>
|
||||||
|
: ReasonReact.null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|> E.L.toArray
|
||||||
|
|> ReasonReact.array}
|
||||||
|
<div className="inline-flex opacity-50 hover:opacity-100">
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_SHOW_STATS)}>
|
<button className=button onClick={_ => dispatch(CHANGE_SHOW_STATS)}>
|
||||||
{"Stats" |> ReasonReact.string}
|
{"Stats" |> ReasonReact.string}
|
||||||
</button>
|
</button>
|
||||||
<button className=button onClick={_ => dispatch(CHANGE_SHOW_PARAMS)}>
|
<button className=button onClick={_ => dispatch(CHANGE_SHOW_PARAMS)}>
|
||||||
{"Params" |> ReasonReact.string}
|
{"Params" |> ReasonReact.string}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button className=button onClick={_ => dispatch(ADD_DIST)}>
|
||||||
className=button
|
{"Add" |> ReasonReact.string}
|
||||||
onClick={_ => dispatch(CHANGE_HEIGHT(state.height + 40))}>
|
|
||||||
{"Expand" |> ReasonReact.string}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
className=button
|
|
||||||
onClick={_ =>
|
|
||||||
dispatch(
|
|
||||||
CHANGE_HEIGHT(
|
|
||||||
state.height < 81 ? state.height : state.height - 40,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}>
|
|
||||||
{"Compress" |> ReasonReact.string}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{state.showParams ? showAsForm(distPlus) : ReasonReact.null}
|
{state.showParams ? showAsForm(distPlus) : ReasonReact.null}
|
||||||
{state.showStats ? table(distPlus, x) : ReasonReact.null}
|
{state.showStats ? table(distPlus, x) : ReasonReact.null}
|
||||||
</div>;
|
</div>;
|
||||||
// chart
|
|
||||||
};
|
};
|
97
src/components/charts/DistPlusPlotReducer.re
Normal file
97
src/components/charts/DistPlusPlotReducer.re
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
type chartConfig = {
|
||||||
|
log: bool,
|
||||||
|
isCumulative: bool,
|
||||||
|
height: int,
|
||||||
|
};
|
||||||
|
|
||||||
|
type state = {
|
||||||
|
log: bool,
|
||||||
|
showStats: bool,
|
||||||
|
showParams: bool,
|
||||||
|
distributions: list(chartConfig),
|
||||||
|
};
|
||||||
|
|
||||||
|
type action =
|
||||||
|
| CHANGE_SHOW_STATS
|
||||||
|
| CHANGE_SHOW_PARAMS
|
||||||
|
| REMOVE_DIST(int)
|
||||||
|
| ADD_DIST
|
||||||
|
| CHANGE_LOG(int)
|
||||||
|
| CHANGE_IS_CUMULATIVE(int, bool)
|
||||||
|
| HEIGHT_INCREMENT(int)
|
||||||
|
| HEIGHT_DECREMENT(int);
|
||||||
|
|
||||||
|
let changeHeight = (currentHeight, foo: [ | `increment | `decrement]) =>
|
||||||
|
switch (currentHeight, foo) {
|
||||||
|
| (1, `decrement) => 1
|
||||||
|
| (2, `decrement) => 1
|
||||||
|
| (3, `decrement) => 2
|
||||||
|
| (4, `decrement) => 3
|
||||||
|
| (1, `increment) => 2
|
||||||
|
| (2, `increment) => 3
|
||||||
|
| (3, `increment) => 4
|
||||||
|
| (4, `increment) => 4
|
||||||
|
| _ => 1
|
||||||
|
};
|
||||||
|
|
||||||
|
let heightToPix =
|
||||||
|
fun
|
||||||
|
| 1 => 80
|
||||||
|
| 2 => 140
|
||||||
|
| 3 => 240
|
||||||
|
| 4 => 340
|
||||||
|
| _ => 140;
|
||||||
|
|
||||||
|
let distributionReducer = (index, state: list(chartConfig), action) => {
|
||||||
|
Js.log3(index, action, state);
|
||||||
|
switch (action, E.L.get(state, index)) {
|
||||||
|
| (HEIGHT_INCREMENT(_), Some(dist)) =>
|
||||||
|
E.L.update(
|
||||||
|
{...dist, height: changeHeight(dist.height, `increment)},
|
||||||
|
index,
|
||||||
|
state,
|
||||||
|
)
|
||||||
|
| (HEIGHT_DECREMENT(_), Some(dist)) =>
|
||||||
|
E.L.update(
|
||||||
|
{...dist, height: changeHeight(dist.height, `decrement)},
|
||||||
|
index,
|
||||||
|
state,
|
||||||
|
)
|
||||||
|
| (CHANGE_IS_CUMULATIVE(_, isCumulative), Some(dist)) =>
|
||||||
|
E.L.update({...dist, isCumulative}, index, state)
|
||||||
|
| (CHANGE_LOG(_), Some(dist)) =>
|
||||||
|
E.L.update({...dist, log: !dist.log}, index, state)
|
||||||
|
| (REMOVE_DIST(_), Some(_)) => E.L.remove(index, 1, state)
|
||||||
|
| (ADD_DIST, Some(_)) =>
|
||||||
|
E.L.append(state, [{log: false, isCumulative: false, height: 2}])
|
||||||
|
| _ => state
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let reducer = (state: state, action: action) =>
|
||||||
|
switch (action) {
|
||||||
|
| CHANGE_LOG(i)
|
||||||
|
| CHANGE_IS_CUMULATIVE(i, _)
|
||||||
|
| HEIGHT_DECREMENT(i)
|
||||||
|
| REMOVE_DIST(i)
|
||||||
|
| HEIGHT_INCREMENT(i) => {
|
||||||
|
...state,
|
||||||
|
distributions: distributionReducer(i, state.distributions, action),
|
||||||
|
}
|
||||||
|
| ADD_DIST => {
|
||||||
|
...state,
|
||||||
|
distributions: distributionReducer(0, state.distributions, action),
|
||||||
|
}
|
||||||
|
| CHANGE_SHOW_STATS => {...state, showStats: !state.showStats}
|
||||||
|
| CHANGE_SHOW_PARAMS => {...state, showParams: !state.showParams}
|
||||||
|
};
|
||||||
|
|
||||||
|
let init = {
|
||||||
|
log: false,
|
||||||
|
showStats: false,
|
||||||
|
showParams: false,
|
||||||
|
distributions: [
|
||||||
|
{log: false, isCumulative: false, height: 2},
|
||||||
|
{log: false, isCumulative: true, height: 1},
|
||||||
|
],
|
||||||
|
};
|
|
@ -177,10 +177,13 @@ module JsDate = {
|
||||||
/* List */
|
/* List */
|
||||||
module L = {
|
module L = {
|
||||||
let fmap = List.map;
|
let fmap = List.map;
|
||||||
|
let get = Belt.List.get;
|
||||||
let toArray = Array.of_list;
|
let toArray = Array.of_list;
|
||||||
let fmapi = List.mapi;
|
let fmapi = List.mapi;
|
||||||
let concat = List.concat;
|
let concat = List.concat;
|
||||||
let append = List.append;
|
let append = List.append;
|
||||||
|
let drop = Rationale.RList.drop;
|
||||||
|
let remove = Rationale.RList.remove;
|
||||||
let find = List.find;
|
let find = List.find;
|
||||||
let filter = List.filter;
|
let filter = List.filter;
|
||||||
let for_all = List.for_all;
|
let for_all = List.for_all;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user