commit
73763cdc40
|
@ -156,7 +156,8 @@ module DistPlusChart = {
|
||||||
let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) =
|
let (yMaxDiscreteDomainFactor, yMaxContinuousDomainFactor) =
|
||||||
adjustBoth(toDiscreteProbabilityMass);
|
adjustBoth(toDiscreteProbabilityMass);
|
||||||
<DistributionPlot
|
<DistributionPlot
|
||||||
scale={config.log ? "log" : "linear"}
|
xScale={config.xLog ? "log" : "linear"}
|
||||||
|
yScale={config.yLog ? "log" : "linear"}
|
||||||
height={DistPlusPlotReducer.heightToPix(config.height)}
|
height={DistPlusPlotReducer.heightToPix(config.height)}
|
||||||
minX
|
minX
|
||||||
maxX
|
maxX
|
||||||
|
@ -191,7 +192,8 @@ 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"}
|
xScale={config.xLog ? "log" : "linear"}
|
||||||
|
yScale={config.yLog ? "log" : "linear"}
|
||||||
height={DistPlusPlotReducer.heightToPix(config.height)}
|
height={DistPlusPlotReducer.heightToPix(config.height)}
|
||||||
minX
|
minX
|
||||||
maxX
|
maxX
|
||||||
|
@ -244,8 +246,13 @@ let make = (~distPlus: DistTypes.distPlus) => {
|
||||||
<div className="opacity-50 hover:opacity-100">
|
<div className="opacity-50 hover:opacity-100">
|
||||||
<button
|
<button
|
||||||
className=button
|
className=button
|
||||||
onClick={_ => dispatch(CHANGE_LOG(index))}>
|
onClick={_ => dispatch(CHANGE_X_LOG(index))}>
|
||||||
{(config.log ? "x-log" : "x-linear") |> ReasonReact.string}
|
{(config.xLog ? "x-log" : "x-linear") |> ReasonReact.string}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className=button
|
||||||
|
onClick={_ => dispatch(CHANGE_Y_LOG(index))}>
|
||||||
|
{(config.yLog ? "y-log" : "y-linear") |> ReasonReact.string}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className=button
|
className=button
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
type chartConfig = {
|
type chartConfig = {
|
||||||
log: bool,
|
xLog: bool,
|
||||||
|
yLog: bool,
|
||||||
isCumulative: bool,
|
isCumulative: bool,
|
||||||
height: int,
|
height: int,
|
||||||
};
|
};
|
||||||
|
@ -15,7 +16,8 @@ type action =
|
||||||
| CHANGE_SHOW_PARAMS
|
| CHANGE_SHOW_PARAMS
|
||||||
| REMOVE_DIST(int)
|
| REMOVE_DIST(int)
|
||||||
| ADD_DIST
|
| ADD_DIST
|
||||||
| CHANGE_LOG(int)
|
| CHANGE_X_LOG(int)
|
||||||
|
| CHANGE_Y_LOG(int)
|
||||||
| CHANGE_IS_CUMULATIVE(int, bool)
|
| CHANGE_IS_CUMULATIVE(int, bool)
|
||||||
| HEIGHT_INCREMENT(int)
|
| HEIGHT_INCREMENT(int)
|
||||||
| HEIGHT_DECREMENT(int);
|
| HEIGHT_DECREMENT(int);
|
||||||
|
@ -42,7 +44,6 @@ let heightToPix =
|
||||||
| _ => 140;
|
| _ => 140;
|
||||||
|
|
||||||
let distributionReducer = (index, state: list(chartConfig), action) => {
|
let distributionReducer = (index, state: list(chartConfig), action) => {
|
||||||
Js.log3(index, action, state);
|
|
||||||
switch (action, E.L.get(state, index)) {
|
switch (action, E.L.get(state, index)) {
|
||||||
| (HEIGHT_INCREMENT(_), Some(dist)) =>
|
| (HEIGHT_INCREMENT(_), Some(dist)) =>
|
||||||
E.L.update(
|
E.L.update(
|
||||||
|
@ -58,18 +59,24 @@ let distributionReducer = (index, state: list(chartConfig), action) => {
|
||||||
)
|
)
|
||||||
| (CHANGE_IS_CUMULATIVE(_, isCumulative), Some(dist)) =>
|
| (CHANGE_IS_CUMULATIVE(_, isCumulative), Some(dist)) =>
|
||||||
E.L.update({...dist, isCumulative}, index, state)
|
E.L.update({...dist, isCumulative}, index, state)
|
||||||
| (CHANGE_LOG(_), Some(dist)) =>
|
| (CHANGE_X_LOG(_), Some(dist)) =>
|
||||||
E.L.update({...dist, log: !dist.log}, index, state)
|
E.L.update({...dist, xLog: !dist.xLog}, index, state)
|
||||||
|
| (CHANGE_Y_LOG(_), Some(dist)) =>
|
||||||
|
E.L.update({...dist, yLog: !dist.yLog}, index, state)
|
||||||
| (REMOVE_DIST(_), Some(_)) => E.L.remove(index, 1, state)
|
| (REMOVE_DIST(_), Some(_)) => E.L.remove(index, 1, state)
|
||||||
| (ADD_DIST, Some(_)) =>
|
| (ADD_DIST, Some(_)) =>
|
||||||
E.L.append(state, [{log: false, isCumulative: false, height: 2}])
|
E.L.append(
|
||||||
|
state,
|
||||||
|
[{yLog: false, xLog: false, isCumulative: false, height: 2}],
|
||||||
|
)
|
||||||
| _ => state
|
| _ => state
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let reducer = (state: state, action: action) =>
|
let reducer = (state: state, action: action) =>
|
||||||
switch (action) {
|
switch (action) {
|
||||||
| CHANGE_LOG(i)
|
| CHANGE_X_LOG(i)
|
||||||
|
| CHANGE_Y_LOG(i)
|
||||||
| CHANGE_IS_CUMULATIVE(i, _)
|
| CHANGE_IS_CUMULATIVE(i, _)
|
||||||
| HEIGHT_DECREMENT(i)
|
| HEIGHT_DECREMENT(i)
|
||||||
| REMOVE_DIST(i)
|
| REMOVE_DIST(i)
|
||||||
|
@ -89,7 +96,7 @@ let init = {
|
||||||
showStats: false,
|
showStats: false,
|
||||||
showParams: false,
|
showParams: false,
|
||||||
distributions: [
|
distributions: [
|
||||||
{log: false, isCumulative: false, height: 2},
|
{yLog: false, xLog: false, isCumulative: false, height: 2},
|
||||||
{log: false, isCumulative: true, height: 1},
|
{yLog: false, xLog: false, isCumulative: true, height: 1},
|
||||||
],
|
],
|
||||||
};
|
};
|
|
@ -29,7 +29,8 @@ module RawPlot = {
|
||||||
~onHover=(f: float) => (),
|
~onHover=(f: float) => (),
|
||||||
~continuous=?,
|
~continuous=?,
|
||||||
~discrete=?,
|
~discrete=?,
|
||||||
~scale=?,
|
~xScale=?,
|
||||||
|
~yScale=?,
|
||||||
~showDistributionLines=?,
|
~showDistributionLines=?,
|
||||||
~showDistributionYAxis=?,
|
~showDistributionYAxis=?,
|
||||||
~showVerticalLine=?,
|
~showVerticalLine=?,
|
||||||
|
@ -51,7 +52,8 @@ module RawPlot = {
|
||||||
~onHover,
|
~onHover,
|
||||||
~continuous?,
|
~continuous?,
|
||||||
~discrete?,
|
~discrete?,
|
||||||
~scale?,
|
~xScale?,
|
||||||
|
~yScale?,
|
||||||
~showDistributionLines?,
|
~showDistributionLines?,
|
||||||
~showDistributionYAxis?,
|
~showDistributionYAxis?,
|
||||||
~showVerticalLine?,
|
~showVerticalLine?,
|
||||||
|
@ -116,7 +118,8 @@ let make =
|
||||||
~yMaxContinuousDomainFactor=?,
|
~yMaxContinuousDomainFactor=?,
|
||||||
~onHover: float => unit=_ => (),
|
~onHover: float => unit=_ => (),
|
||||||
~continuous=?,
|
~continuous=?,
|
||||||
~scale=?,
|
~xScale=?,
|
||||||
|
~yScale=?,
|
||||||
~showDistributionLines=false,
|
~showDistributionLines=false,
|
||||||
~showDistributionYAxis=false,
|
~showDistributionYAxis=false,
|
||||||
~showVerticalLine=false,
|
~showVerticalLine=false,
|
||||||
|
@ -128,7 +131,8 @@ let make =
|
||||||
?minX
|
?minX
|
||||||
?yMaxDiscreteDomainFactor
|
?yMaxDiscreteDomainFactor
|
||||||
?yMaxContinuousDomainFactor
|
?yMaxContinuousDomainFactor
|
||||||
?scale
|
?xScale
|
||||||
|
?yScale
|
||||||
?timeScale
|
?timeScale
|
||||||
discrete={discrete |> E.O.fmap(XYShape.toJs)}
|
discrete={discrete |> E.O.fmap(XYShape.toJs)}
|
||||||
height
|
height
|
||||||
|
|
|
@ -32,11 +32,20 @@ export class DistPlotD3 {
|
||||||
xScaleLogBase: 10,
|
xScaleLogBase: 10,
|
||||||
|
|
||||||
// Y
|
// Y
|
||||||
|
minY: null,
|
||||||
|
maxY: null,
|
||||||
|
yScaleType: 'linear',
|
||||||
|
yScaleTimeOptions: null,
|
||||||
|
yScaleLogBase: 10,
|
||||||
|
|
||||||
|
xMinContinuousDomainFactor: 1,
|
||||||
|
xMaxContinuousDomainFactor: 1,
|
||||||
yMaxContinuousDomainFactor: 1,
|
yMaxContinuousDomainFactor: 1,
|
||||||
yMaxDiscreteDomainFactor: 1,
|
yMaxDiscreteDomainFactor: 1,
|
||||||
showDistributionYAxis: false,
|
|
||||||
|
|
||||||
|
showDistributionYAxis: false,
|
||||||
showDistributionLines: true,
|
showDistributionLines: true,
|
||||||
|
|
||||||
areaColors: ['#E1E5EC', '#E1E5EC'],
|
areaColors: ['#E1E5EC', '#E1E5EC'],
|
||||||
verticalLine: 110,
|
verticalLine: 110,
|
||||||
showVerticalLine: true,
|
showVerticalLine: true,
|
||||||
|
@ -65,7 +74,7 @@ export class DistPlotD3 {
|
||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param value
|
* @param value
|
||||||
* @returns {CdfChartD3}
|
* @returns {DistPlotD3}
|
||||||
*/
|
*/
|
||||||
set(name, value) {
|
set(name, value) {
|
||||||
_.set(this.attrs, [name], value);
|
_.set(this.attrs, [name], value);
|
||||||
|
@ -74,7 +83,7 @@ export class DistPlotD3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param data
|
* @param data
|
||||||
* @returns {CdfChartD3}
|
* @returns {DistPlotD3}
|
||||||
*/
|
*/
|
||||||
data(data) {
|
data(data) {
|
||||||
const continuousXs = _.get(data, 'continuous.xs', []);
|
const continuousXs = _.get(data, 'continuous.xs', []);
|
||||||
|
@ -102,11 +111,18 @@ export class DistPlotD3 {
|
||||||
if (!['log', 'linear'].includes(this.attrs.xScaleType)) {
|
if (!['log', 'linear'].includes(this.attrs.xScaleType)) {
|
||||||
throw new Error('X-scale type should be either "log" or "linear".');
|
throw new Error('X-scale type should be either "log" or "linear".');
|
||||||
}
|
}
|
||||||
|
if (!['log', 'linear'].includes(this.attrs.yScaleType)) {
|
||||||
|
throw new Error('Y-scale type should be either "log" or "linear".');
|
||||||
|
}
|
||||||
|
|
||||||
// Log Scale.
|
// Log Scale.
|
||||||
if (this.attrs.xScaleType === 'log') {
|
if (this.attrs.xScaleType === 'log') {
|
||||||
this.logFilter('continuous');
|
this.logFilter('continuous', (x, y) => x > 0);
|
||||||
this.logFilter('discrete');
|
this.logFilter('discrete', (x, y) => x > 0);
|
||||||
|
}
|
||||||
|
if (this.attrs.yScaleType === 'log') {
|
||||||
|
this.logFilter('continuous', (x, y) => y > 0);
|
||||||
|
this.logFilter('discrete', (x, y) => y > 0);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
this.attrs.xScaleType === 'log'
|
this.attrs.xScaleType === 'log'
|
||||||
|
@ -116,6 +132,14 @@ export class DistPlotD3 {
|
||||||
console.warn('minX should be positive.');
|
console.warn('minX should be positive.');
|
||||||
this.attrs.minX = undefined;
|
this.attrs.minX = undefined;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
this.attrs.yScaleType === 'log'
|
||||||
|
&& this.attrs.minY !== null
|
||||||
|
&& this.attrs.minY < 0
|
||||||
|
) {
|
||||||
|
console.warn('minY should be positive.');
|
||||||
|
this.attrs.minY = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
// Fields.
|
// Fields.
|
||||||
const fields = [
|
const fields = [
|
||||||
|
@ -124,7 +148,7 @@ export class DistPlotD3 {
|
||||||
'svgWidth', 'svgHeight',
|
'svgWidth', 'svgHeight',
|
||||||
'yMaxContinuousDomainFactor',
|
'yMaxContinuousDomainFactor',
|
||||||
'yMaxDiscreteDomainFactor',
|
'yMaxDiscreteDomainFactor',
|
||||||
'xScaleLogBase',
|
'xScaleLogBase', 'yScaleLogBase',
|
||||||
];
|
];
|
||||||
for (const field of fields) {
|
for (const field of fields) {
|
||||||
if (!_.isNumber(this.attrs[field])) {
|
if (!_.isNumber(this.attrs[field])) {
|
||||||
|
@ -212,10 +236,14 @@ export class DistPlotD3 {
|
||||||
if (!_.isFinite(yMax)) throw new Error('yMax is undefined');
|
if (!_.isFinite(yMax)) throw new Error('yMax is undefined');
|
||||||
|
|
||||||
// X-domains.
|
// X-domains.
|
||||||
|
const xMinDomainFactor = _.get(this.attrs, 'xMinContinuousDomainFactor', 1);
|
||||||
|
const xMaxDomainFactor = _.get(this.attrs, 'xMaxContinuousDomainFactor', 1);
|
||||||
|
const yMinDomainFactor = _.get(this.attrs, 'yMinContinuousDomainFactor', 1);
|
||||||
const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1);
|
const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1);
|
||||||
const xMinDomain = xMin;
|
|
||||||
const xMaxDomain = xMax;
|
const xMinDomain = xMin * xMinDomainFactor;
|
||||||
const yMinDomain = yMin;
|
const xMaxDomain = xMax * xMaxDomainFactor;
|
||||||
|
const yMinDomain = yMin * yMinDomainFactor;
|
||||||
const yMaxDomain = yMax * yMaxDomainFactor;
|
const yMaxDomain = yMax * yMaxDomainFactor;
|
||||||
|
|
||||||
// X-scale.
|
// X-scale.
|
||||||
|
@ -229,9 +257,14 @@ export class DistPlotD3 {
|
||||||
.range([0, this.calc.chartWidth]);
|
.range([0, this.calc.chartWidth]);
|
||||||
|
|
||||||
// Y-scale.
|
// Y-scale.
|
||||||
const yScale = d3.scaleLinear()
|
const yScale = this.attrs.yScaleType === 'linear'
|
||||||
.domain([yMinDomain, yMaxDomain])
|
? d3.scaleLinear()
|
||||||
.range([this.calc.chartHeight, 0]);
|
.domain([yMinDomain, yMaxDomain])
|
||||||
|
.range([this.calc.chartHeight, 0])
|
||||||
|
: d3.scaleLog()
|
||||||
|
.base(this.attrs.yScaleLogBase)
|
||||||
|
.domain([yMinDomain, yMaxDomain])
|
||||||
|
.range([this.calc.chartHeight, 0]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
xMin, xMax,
|
xMin, xMax,
|
||||||
|
@ -394,7 +427,7 @@ export class DistPlotD3 {
|
||||||
addLollipopsChart(common) {
|
addLollipopsChart(common) {
|
||||||
const data = this.getDataPoints('discrete');
|
const data = this.getDataPoints('discrete');
|
||||||
|
|
||||||
const _yMin = d3.min(this.attrs.data.discrete.ys);
|
const yMin = d3.min(this.attrs.data.discrete.ys);
|
||||||
const yMax = d3.max(this.attrs.data.discrete.ys);
|
const yMax = d3.max(this.attrs.data.discrete.ys);
|
||||||
|
|
||||||
// X axis.
|
// X axis.
|
||||||
|
@ -404,15 +437,22 @@ export class DistPlotD3 {
|
||||||
.call(d3.axisBottom(common.xScale));
|
.call(d3.axisBottom(common.xScale));
|
||||||
|
|
||||||
// Y-domain.
|
// Y-domain.
|
||||||
|
const yMinDomainFactor = _.get(this.attrs, 'yMinDiscreteDomainFactor', 1);
|
||||||
const yMaxDomainFactor = _.get(this.attrs, 'yMaxDiscreteDomainFactor', 1);
|
const yMaxDomainFactor = _.get(this.attrs, 'yMaxDiscreteDomainFactor', 1);
|
||||||
const yMinDomain = 0;
|
const yMinDomain = yMin * yMinDomainFactor;
|
||||||
const yMaxDomain = yMax * yMaxDomainFactor;
|
const yMaxDomain = yMax * yMaxDomainFactor;
|
||||||
|
|
||||||
// Y-scale.
|
// Y-scale.
|
||||||
const yScale = d3.scaleLinear()
|
const yScale = this.attrs.yScaleType === 'linear'
|
||||||
.domain([yMinDomain, yMaxDomain])
|
? d3.scaleLinear()
|
||||||
.range([this.calc.chartHeight, 0]);
|
.domain([yMinDomain, yMaxDomain])
|
||||||
|
.range([this.calc.chartHeight, 0])
|
||||||
|
: d3.scaleLog()
|
||||||
|
.base(this.attrs.yScaleLogBase)
|
||||||
|
.domain([yMinDomain, yMaxDomain])
|
||||||
|
.range([this.calc.chartHeight, 0]);
|
||||||
|
|
||||||
|
//
|
||||||
const yTicks = Math.floor(this.calc.chartHeight / 20);
|
const yTicks = Math.floor(this.calc.chartHeight / 20);
|
||||||
const yAxis = d3.axisLeft(yScale).ticks(yTicks);
|
const yAxis = d3.axisLeft(yScale).ticks(yTicks);
|
||||||
|
|
||||||
|
@ -457,7 +497,7 @@ export class DistPlotD3 {
|
||||||
.attr('x1', d => common.xScale(d.x))
|
.attr('x1', d => common.xScale(d.x))
|
||||||
.attr('x2', d => common.xScale(d.x))
|
.attr('x2', d => common.xScale(d.x))
|
||||||
.attr('y1', d => yScale(d.y))
|
.attr('y1', d => yScale(d.y))
|
||||||
.attr('y2', yScale(0));
|
.attr('y2', yScale(yMin));
|
||||||
|
|
||||||
// Define the div for the tooltip
|
// Define the div for the tooltip
|
||||||
const tooltip = this._container.append('div')
|
const tooltip = this._container.append('div')
|
||||||
|
@ -552,9 +592,10 @@ export class DistPlotD3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} key
|
* @param {string} key
|
||||||
|
* @param {function} pred
|
||||||
* @returns {{x: number[], y: number[]}}
|
* @returns {{x: number[], y: number[]}}
|
||||||
*/
|
*/
|
||||||
logFilter(key) {
|
logFilter(key, pred) {
|
||||||
const xs = [];
|
const xs = [];
|
||||||
const ys = [];
|
const ys = [];
|
||||||
const emptyShape = { xs: [], ys: [] };
|
const emptyShape = { xs: [], ys: [] };
|
||||||
|
@ -563,7 +604,7 @@ export class DistPlotD3 {
|
||||||
for (let i = 0, len = data.xs.length; i < len; i++) {
|
for (let i = 0, len = data.xs.length; i < len; i++) {
|
||||||
const x = data.xs[i];
|
const x = data.xs[i];
|
||||||
const y = data.ys[i];
|
const y = data.ys[i];
|
||||||
if (x > 0) {
|
if (pred(x, y)) {
|
||||||
xs.push(x);
|
xs.push(x);
|
||||||
ys.push(y);
|
ys.push(y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@ function getRandomInt(min, max) {
|
||||||
function DistPlotReact(props) {
|
function DistPlotReact(props) {
|
||||||
const containerRef = React.createRef();
|
const containerRef = React.createRef();
|
||||||
const key = "cdf-chart-react-" + getRandomInt(0, 1000);
|
const key = "cdf-chart-react-" + getRandomInt(0, 1000);
|
||||||
const scale = props.scale || 'linear';
|
|
||||||
const style = !!props.width ? { width: props.width + "px" } : {};
|
const style = !!props.width ? { width: props.width + "px" } : {};
|
||||||
|
|
||||||
const [sized, { width }] = useSize(() => {
|
const [sized, { width }] = useSize(() => {
|
||||||
|
@ -49,7 +48,8 @@ function DistPlotReact(props) {
|
||||||
.set('verticalLine', props.verticalLine || 110)
|
.set('verticalLine', props.verticalLine || 110)
|
||||||
.set('showVerticalLine', props.showVerticalLine)
|
.set('showVerticalLine', props.showVerticalLine)
|
||||||
.set('container', containerRef.current)
|
.set('container', containerRef.current)
|
||||||
.set('xScaleType', scale)
|
.set('xScaleType', props.xScale || 'linear')
|
||||||
|
.set('yScaleType', props.yScale || 'linear')
|
||||||
.set('xScaleTimeOptions', props.timeScale)
|
.set('xScaleTimeOptions', props.timeScale)
|
||||||
.set('yMaxContinuousDomainFactor', props.yMaxContinuousDomainFactor || 1)
|
.set('yMaxContinuousDomainFactor', props.yMaxContinuousDomainFactor || 1)
|
||||||
.set('yMaxDiscreteDomainFactor', props.yMaxDiscreteDomainFactor || 1)
|
.set('yMaxDiscreteDomainFactor', props.yMaxDiscreteDomainFactor || 1)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user