Merge pull request #14 from foretold-app/improvements/1100

Improvements/1100
This commit is contained in:
Ozzie Gooen 2020-03-03 08:52:42 +00:00 committed by GitHub
commit f1f75df73b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 93 additions and 21 deletions

View File

@ -78,7 +78,7 @@ module Menu = {
<Item href={routeToPath(DistBuilder)} key="dist-builder"> <Item href={routeToPath(DistBuilder)} key="dist-builder">
{"Dist Builder" |> E.ste} {"Dist Builder" |> E.ste}
</Item> </Item>
<Item href={routeToPath(DistBuilder2)} key="dist-builder"> <Item href={routeToPath(DistBuilder2)} key="dist-builder-2">
{"Dist Builder 2" |> E.ste} {"Dist Builder 2" |> E.ste}
</Item> </Item>
</div>; </div>;

View File

@ -38,7 +38,7 @@ module DemoDist = {
let continuous: DistTypes.xyShape = {xs, ys}; let continuous: DistTypes.xyShape = {xs, ys};
<Antd.Card title={"Distribution" |> E.ste}> <Antd.Card title={"Distribution" |> E.ste}>
<div className=Styles.spacer /> <div className=Styles.spacer />
<DistributionPlot height=200 continuous /> <DistributionPlot continuous />
</Antd.Card>; </Antd.Card>;
}; };
}; };

View File

@ -208,4 +208,4 @@ let make = (~distPlus: DistTypes.distPlus) => {
); );
<div> chart chart2 {table(distPlus, x)} </div>; <div> chart chart2 {table(distPlus, x)} </div>;
// chart // chart
}; };

View File

@ -12,15 +12,14 @@ export class CdfChartD3 {
this.attrs = { this.attrs = {
svgWidth: 400, svgWidth: 400,
svgHeight: 400, svgHeight: 400,
marginTop: 5, marginTop: 5,
marginBottom: 5, marginBottom: 5,
marginRight: 50, marginRight: 50,
marginLeft: 5, marginLeft: 5,
container: null, container: null,
minX: false, minX: null,
maxX: false, maxX: null,
scale: 'linear', scale: 'linear',
timeScale: null, timeScale: null,
showDistributionLines: true, showDistributionLines: true,
@ -54,11 +53,20 @@ export class CdfChartD3 {
this.formatDates = this.formatDates.bind(this); this.formatDates = this.formatDates.bind(this);
} }
/**
* @param {string} name
* @param value
* @returns {CdfChartD3}
*/
set(name, value) { set(name, value) {
_.set(this.attrs, [name], value); _.set(this.attrs, [name], value);
return this; return this;
} }
/**
* @param data
* @returns {CdfChartD3}
*/
data(data) { data(data) {
this.attrs.data = data; this.attrs.data = data;
this.attrs.data.continuous = data.continuous || { this.attrs.data.continuous = data.continuous || {
@ -78,6 +86,42 @@ export class CdfChartD3 {
console.error('Container for D3 is not defined.'); console.error('Container for D3 is not defined.');
return; return;
} }
if (!['log', 'linear'].includes(this.attrs.scale)) {
console.error('Scale should be either "log" or "linear".');
return;
}
// Log Scale.
if (this.attrs.scale === 'log') {
this.logFilter('continuous');
this.logFilter('discrete');
}
if (
this.attrs.scale === 'log'
&& this.attrs.minX !== null
&& this.attrs.minX < 0
) {
console.warn('minX should be positive.');
this.attrs.minX = undefined;
}
// Fields.
const fields = [
'marginLeft', 'marginRight',
'marginTop', 'marginBottom',
'svgWidth', 'svgHeight',
'yMaxContinuousDomainFactor',
'yMaxDiscreteDomainFactor',
'logBase',
];
for (const field of fields) {
if (!_.isNumber(this.attrs[field])) {
console.error(`${field} should be a number.`);
return;
}
}
// Sets the width from the DOM element. // Sets the width from the DOM element.
const containerRect = this._container.node().getBoundingClientRect(); const containerRect = this._container.node().getBoundingClientRect();
if (containerRect.width > 0) { if (containerRect.width > 0) {
@ -134,6 +178,12 @@ export class CdfChartD3 {
const yMin = d3.min(this.attrs.data.continuous.ys); const yMin = d3.min(this.attrs.data.continuous.ys);
const yMax = d3.max(this.attrs.data.continuous.ys); const yMax = d3.max(this.attrs.data.continuous.ys);
// Errors.
if (!_.isFinite(xMin)) return console.error('xMin is undefined');
if (!_.isFinite(xMax)) return console.error('xMax is undefined');
if (!_.isFinite(yMin)) return console.error('yMin is undefined');
if (!_.isFinite(yMax)) return console.error('yMax is undefined');
// X-domains. // X-domains.
const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1); const yMaxDomainFactor = _.get(this.attrs, 'yMaxContinuousDomainFactor', 1);
const xMinDomain = xMin; const xMinDomain = xMin;
@ -142,7 +192,7 @@ export class CdfChartD3 {
const yMaxDomain = yMax * yMaxDomainFactor; const yMaxDomain = yMax * yMaxDomainFactor;
// X-scale. // X-scale.
let xScale = this.attrs.scale === 'linear' const xScale = this.attrs.scale === 'linear'
? d3.scaleLinear() ? d3.scaleLinear()
.domain([xMinDomain, xMaxDomain]) .domain([xMinDomain, xMaxDomain])
.range([0, this.calc.chartWidth]) .range([0, this.calc.chartWidth])
@ -210,16 +260,6 @@ export class CdfChartD3 {
// Y-axis. // Y-axis.
const yAxis = d3.axisRight(yScale); const yAxis = d3.axisRight(yScale);
// Objects.
const line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y));
const area = d3.area()
.x(d => xScale(d.x))
.y1(d => yScale(d.y))
.y0(this.calc.chartHeight);
// Add axis. // Add axis.
this.chart this.chart
.createObject({ tag: 'g', selector: 'x-axis' }) .createObject({ tag: 'g', selector: 'x-axis' })
@ -233,6 +273,11 @@ export class CdfChartD3 {
} }
// Draw area. // Draw area.
const area = d3.area()
.x(d => xScale(d.x))
.y1(d => yScale(d.y))
.y0(this.calc.chartHeight);
this.chart this.chart
.createObjectsWithData({ .createObjectsWithData({
tag: 'path', tag: 'path',
@ -245,6 +290,10 @@ export class CdfChartD3 {
// Draw line. // Draw line.
if (this.attrs.showDistributionLines) { if (this.attrs.showDistributionLines) {
const line = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y));
this.chart this.chart
.createObjectsWithData({ .createObjectsWithData({
tag: 'path', tag: 'path',
@ -454,7 +503,7 @@ export class CdfChartD3 {
} }
/** /**
* @param {name} key * @param {string} key
* @returns {{x: number[], y: number[]}} * @returns {{x: number[], y: number[]}}
*/ */
getDataPoints(key) { getDataPoints(key) {
@ -473,6 +522,29 @@ export class CdfChartD3 {
return dt; return dt;
} }
/**
* @param {string} key
* @returns {{x: number[], y: number[]}}
*/
logFilter(key) {
const xs = [];
const ys = [];
const emptyShape = { xs: [], ys: [] };
const data = _.get(this.attrs.data, key, emptyShape);
for (let i = 0, len = data.xs.length; i < len; i++) {
const x = data.xs[i];
const y = data.ys[i];
if (x > 0) {
xs.push(x);
ys.push(y);
}
}
_.set(this.attrs.data, [key, 'xs'], xs);
_.set(this.attrs.data, [key, 'ys'], ys);
}
/** /**
* @param {string} key * @param {string} key
* @returns {boolean} * @returns {boolean}

View File

@ -46,13 +46,13 @@ function CdfChartReact(props) {
.set('marginTop', 5) .set('marginTop', 5)
.set('showDistributionLines', props.showDistributionLines) .set('showDistributionLines', props.showDistributionLines)
.set('showDistributionYAxis', props.showDistributionYAxis) .set('showDistributionYAxis', props.showDistributionYAxis)
.set('verticalLine', props.verticalLine) .set('verticalLine', props.verticalLine || 110)
.set('showVerticalLine', props.showVerticalLine) .set('showVerticalLine', props.showVerticalLine)
.set('container', containerRef.current) .set('container', containerRef.current)
.set('scale', scale) .set('scale', scale)
.set('timeScale', props.timeScale) .set('timeScale', props.timeScale)
.set('yMaxContinuousDomainFactor', props.yMaxContinuousDomainFactor) .set('yMaxContinuousDomainFactor', props.yMaxContinuousDomainFactor || 1)
.set('yMaxDiscreteDomainFactor', props.yMaxDiscreteDomainFactor) .set('yMaxDiscreteDomainFactor', props.yMaxDiscreteDomainFactor || 1)
.data({ .data({
continuous: props.continuous, continuous: props.continuous,
discrete: props.discrete, discrete: props.discrete,