Skip to content

Commit edcfe7e

Browse files
committed
Merge pull request #91 from plotly/better-errorbars
Some error bar clean ups
2 parents eac41fe + 66ce3fa commit edcfe7e

File tree

11 files changed

+329
-214
lines changed

11 files changed

+329
-214
lines changed

devtools/image_viewer/viewer.js

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
var fs = require('fs');
2+
var path = require('path');
23

34
var d3 = require('d3');
45

5-
var constants = require('../../tasks/util/constants');
6-
7-
86
var $plotlist = document.getElementById('plot-list'),
97
$images = document.getElementById('plot-images'),
108
$mock = document.getElementById('plot-mock');
119

12-
var dirBaseline = constants.pathToTestImageBaselines,
13-
dirTest = constants.pathToTestImages,
14-
dirDiff = constants.pathToTestImagesDiff,
15-
dirMocks = constants.pathToTestImageMocks;
10+
var pathToRoot = path.join(__dirname, '../../'),
11+
pathToImageTest = path.join(pathToRoot, 'test/image'),
12+
pathToBuild = path.join(pathToRoot, 'build/'),
13+
dirMocks = path.join(pathToImageTest, 'mocks/'),
14+
dirBaseline = path.join(pathToImageTest, 'baselines/'),
15+
dirTest = path.join(pathToBuild, 'test_images/'),
16+
dirDiff = path.join(pathToBuild, 'test_images_diff/');
1617

1718
// N.B. brfs only understand hard-coded paths
1819
var imageNames = fs.readFileSync(

src/components/errorbars/calc.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright 2012-2015, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
var isNumeric = require('fast-isnumeric');
13+
14+
var Plots = require('../../plots/plots');
15+
var Axes = require('../../plots/cartesian/axes');
16+
17+
var makeComputeError = require('./compute_error');
18+
19+
20+
module.exports = function calc(gd) {
21+
var calcdata = gd.calcdata;
22+
23+
for(var i = 0; i < calcdata.length; i++) {
24+
var calcTrace = calcdata[i],
25+
trace = calcTrace[0].trace;
26+
27+
if(!Plots.traceIs(trace, 'errorBarsOK')) continue;
28+
29+
var xa = Axes.getFromId(gd, trace.xaxis),
30+
ya = Axes.getFromId(gd, trace.yaxis);
31+
32+
calcOneAxis(calcTrace, trace, xa, 'x');
33+
calcOneAxis(calcTrace, trace, ya, 'y');
34+
}
35+
};
36+
37+
function calcOneAxis(calcTrace, trace, axis, coord) {
38+
var opts = trace['error_' + coord] || {},
39+
isVisible = (opts.visible && ['linear', 'log'].indexOf(axis.type) !== -1),
40+
vals = [];
41+
42+
if(!isVisible) return;
43+
44+
var computeError = makeComputeError(opts);
45+
46+
for(var i = 0; i < calcTrace.length; i++) {
47+
var calcPt = calcTrace[i],
48+
calcCoord = calcPt[coord];
49+
50+
if(!isNumeric(axis.c2l(calcCoord))) continue;
51+
52+
var errors = computeError(calcCoord, i);
53+
if(isNumeric(errors[0]) && isNumeric(errors[1])) {
54+
var shoe = calcPt[coord + 's'] = calcCoord - errors[0],
55+
hat = calcPt[coord + 'h'] = calcCoord + errors[1];
56+
vals.push(shoe, hat);
57+
}
58+
}
59+
60+
Axes.expand(axis, vals, {padded: true});
61+
}
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* Copyright 2012-2015, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
10+
'use strict';
11+
12+
13+
/**
14+
* Error bar computing function generator
15+
*
16+
* N.B. The generated function does not clean the dataPt entries. Non-numeric
17+
* entries result in undefined error magnitudes.
18+
*
19+
* @param {object} opts error bar attributes
20+
*
21+
* @return {function} :
22+
* @param {numeric} dataPt data point from where to compute the error magnitude
23+
* @param {number} index index of dataPt in its corresponding data array
24+
* @return {array}
25+
* - error[0] : error magnitude in the negative direction
26+
* - error[1] : " " " " positive "
27+
*/
28+
module.exports = function makeComputeError(opts) {
29+
var type = opts.type,
30+
symmetric = opts.symmetric;
31+
32+
if(type === 'data') {
33+
var array = opts.array,
34+
arrayminus = opts.arrayminus;
35+
36+
if(symmetric || arrayminus === undefined) {
37+
return function computeError(dataPt, index) {
38+
var val = +(array[index]);
39+
return [val, val];
40+
};
41+
}
42+
else {
43+
return function computeError(dataPt, index) {
44+
return [+arrayminus[index], +array[index]];
45+
};
46+
}
47+
}
48+
else {
49+
var computeErrorValue = makeComputeErrorValue(type, opts.value),
50+
computeErrorValueMinus = makeComputeErrorValue(type, opts.valueminus);
51+
52+
if(symmetric || opts.valueminus === undefined) {
53+
return function computeError(dataPt) {
54+
var val = computeErrorValue(dataPt);
55+
return [val, val];
56+
};
57+
}
58+
else {
59+
return function computeError(dataPt) {
60+
return [
61+
computeErrorValueMinus(dataPt),
62+
computeErrorValue(dataPt)
63+
];
64+
};
65+
}
66+
}
67+
};
68+
69+
/**
70+
* Compute error bar magnitude (for all types except data)
71+
*
72+
* @param {string} type error bar type
73+
* @param {numeric} value error bar value
74+
*
75+
* @return {function} :
76+
* @param {numeric} dataPt
77+
*/
78+
function makeComputeErrorValue(type, value) {
79+
if(type === 'percent') {
80+
return function(dataPt) {
81+
return Math.abs(dataPt * value / 100);
82+
};
83+
}
84+
if(type === 'constant') {
85+
return function() {
86+
return Math.abs(value);
87+
};
88+
}
89+
if(type === 'sqrt') {
90+
return function(dataPt) {
91+
return Math.sqrt(Math.abs(dataPt));
92+
};
93+
}
94+
}

src/components/errorbars/defaults.js

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/**
2+
* Copyright 2012-2015, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var isNumeric = require('fast-isnumeric');
12+
13+
var Plots = require('../../plots/plots');
14+
var Lib = require('../../lib');
15+
16+
var attributes = require('./attributes');
17+
18+
19+
module.exports = function(traceIn, traceOut, defaultColor, opts) {
20+
var objName = 'error_' + opts.axis,
21+
containerOut = traceOut[objName] = {},
22+
containerIn = traceIn[objName] || {};
23+
24+
function coerce (attr, dflt) {
25+
return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
26+
}
27+
28+
var hasErrorBars = (
29+
containerIn.array !== undefined ||
30+
containerIn.value !== undefined ||
31+
containerIn.type === 'sqrt'
32+
);
33+
34+
var visible = coerce('visible', hasErrorBars);
35+
36+
if(visible === false) return;
37+
38+
var type = coerce('type', 'array' in containerIn ? 'data' : 'percent'),
39+
symmetric = true;
40+
41+
if(type !== 'sqrt') {
42+
symmetric = coerce('symmetric',
43+
!((type === 'data' ? 'arrayminus' : 'valueminus') in containerIn));
44+
}
45+
46+
if(type === 'data') {
47+
var array = coerce('array');
48+
if(!array) containerOut.array = [];
49+
coerce('traceref');
50+
if(!symmetric) {
51+
var arrayminus = coerce('arrayminus');
52+
if(!arrayminus) containerOut.arrayminus = [];
53+
coerce('tracerefminus');
54+
}
55+
}
56+
else if(type==='percent' || type==='constant') {
57+
coerce('value');
58+
if(!symmetric) coerce('valueminus');
59+
}
60+
61+
var copyAttr = 'copy_'+opts.inherit+'style';
62+
if(opts.inherit) {
63+
var inheritObj = traceOut['error_' + opts.inherit];
64+
if((inheritObj||{}).visible) {
65+
coerce(copyAttr, !(containerIn.color ||
66+
isNumeric(containerIn.thickness) ||
67+
isNumeric(containerIn.width)));
68+
}
69+
}
70+
if(!opts.inherit || !containerOut[copyAttr]) {
71+
coerce('color', defaultColor);
72+
coerce('thickness');
73+
coerce('width', Plots.traceIs(traceOut, 'gl3d') ? 0 : 4);
74+
}
75+
};

0 commit comments

Comments
 (0)