Skip to content
15 changes: 8 additions & 7 deletions devtools/image_viewer/viewer.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
var fs = require('fs');
var path = require('path');

var d3 = require('d3');

var constants = require('../../tasks/util/constants');


var $plotlist = document.getElementById('plot-list'),
$images = document.getElementById('plot-images'),
$mock = document.getElementById('plot-mock');

var dirBaseline = constants.pathToTestImageBaselines,
dirTest = constants.pathToTestImages,
dirDiff = constants.pathToTestImagesDiff,
dirMocks = constants.pathToTestImageMocks;
var pathToRoot = path.join(__dirname, '../../'),
pathToImageTest = path.join(pathToRoot, 'test/image'),
pathToBuild = path.join(pathToRoot, 'build/'),
dirMocks = path.join(pathToImageTest, 'mocks/'),
dirBaseline = path.join(pathToImageTest, 'baselines/'),
dirTest = path.join(pathToBuild, 'test_images/'),
dirDiff = path.join(pathToBuild, 'test_images_diff/');

// N.B. brfs only understand hard-coded paths
var imageNames = fs.readFileSync(
Expand Down
69 changes: 69 additions & 0 deletions src/components/errorbars/calc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Copyright 2012-2015, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var isNumeric = require('fast-isnumeric');

var Plots = require('../../plots/plots');
var Axes = require('../../plots/cartesian/axes');

var makeComputeError = require('./compute_error');


module.exports = function calc(gd) {
var calcdata = gd.calcdata;

for(var i = 0; i < calcdata.length; i++) {
var calcTrace = calcdata[i],
trace = calcTrace[0].trace;

if(!Plots.traceIs(trace, 'errorBarsOK')) continue;

var xOpts = trace.error_x || {},
yOpts = trace.error_y || {},
xa = Axes.getFromId(gd, trace.xaxis),
ya = Axes.getFromId(gd, trace.yaxis),
xVis = (xOpts.visible && ['linear', 'log'].indexOf(xa.type) !== -1),
yVis = (yOpts.visible && ['linear', 'log'].indexOf(ya.type) !== -1);

if(!xVis && !yVis) continue;

var xVals = [],
yVals = [];

var computeErrorY = makeComputeError(yOpts),
computeErrorX = makeComputeError(xOpts);

for(var j = 0; j < calcTrace.length; j++) {
var calcPt = calcTrace[j],
calcY = calcPt.y,
calcX = calcPt.x;

if(!isNumeric(ya.c2l(calcY)) || !isNumeric(xa.c2l(calcX))) continue;

var errorY = computeErrorY(calcY, j);
if(isNumeric(errorY[0]) && isNumeric(errorY[1])) {
calcPt.ys = calcY - errorY[0];
calcPt.yh = calcY + errorY[1];
yVals.push(calcPt.ys, calcPt.yh);
}

var errorX = computeErrorX(calcX, j);
if(isNumeric(errorX[0]) && isNumeric(errorX[1])) {
calcPt.xs = calcX - errorX[0];
calcPt.xh = calcX + errorX[1];
xVals.push(calcPt.xs, calcPt.xh);
}
}

Axes.expand(ya, yVals, {padded: true});
Axes.expand(xa, xVals, {padded: true});
}
};
82 changes: 82 additions & 0 deletions src/components/errorbars/compute_error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Copyright 2012-2015, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/


'use strict';


/**
* Error bar computing function generator
*
* N.B. This function does not clean the dataPt entries, non-numeric
* entries result in undefined *error*
*
* @param {object} opts error bar attributes
*
* @return {function} :
* @param {numeric} dataVal error magnitude in the negative direction
* @param {number} index index of dataPt in its corresponding data array
* @return {array}
* - error[0] : error magnitude in the negative direction
* - error[1] : " " " " positive "
*/
module.exports = function makeComputeError(opts) {
var type = opts.type,
symmetric = opts.symmetric;

if(type === 'data') {
var array = opts.array,
arrayminus = opts.arrayminus;

if(symmetric || arrayminus === undefined) {
return function computeError(dataPt, index) {
var val = +(array[index]);
return [val, val];
};
}
else {
return function computeError(dataPt, index) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return [+arrayminus[index], +array[index]];
};
}
}
else {
var value = opts.value,
valueminus = opts.valueminus;

if(symmetric || valueminus === undefined) {
return function computeError(dataPt) {
var val = getErrorVal(type, dataPt, value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not to be pedantic, but you're still switching on type many times, you could do it once:

function getErrorFunction(type) {
    if(type === 'percent') return function(dataPt, value) {
        return Math.abs(dataPt * value / 100);
    }
    // etc
}

and then here:

var value = opts.value,
    valueminus = opts.valueminus,
    errorfunc = getErrorFunction(type);

if(symmetric || valueminus === undefined) {
    return function(dataPt) {
        var val = errorFunc(dataPt, value);
        return [val, val];
    }
}
else {
    return function(dataPt) {
        return [
            errorFunc(dataPt, value),
            errorFunc(dataPt, valueminus)
        ];
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point. all about the 🐎

We have quite a few of these reusable calc functions, might as well set a good benchmark for them now.

return [val, val];
};
}
else {
return function computeError(dataPt) {
return [
getErrorVal(type, dataPt, valueminus),
getErrorVal(type, dataPt, value)
];
};
}
}
};

/**
* Compute error bar magnitude (for all types except data)
*
* @param {string} type error bar type
* @param {numeric} dataPt
* data point from where to compute the error magnitude
* @param {numeric} [value] error bar value
*
*/
function getErrorVal(type, dataPt, value) {
if(type === 'percent') return Math.abs(dataPt * value / 100);
if(type === 'constant') return Math.abs(value);
if(type === 'sqrt') return Math.sqrt(Math.abs(dataPt));
}
75 changes: 75 additions & 0 deletions src/components/errorbars/defaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* Copyright 2012-2015, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

'use strict';

var isNumeric = require('fast-isnumeric');

var Plots = require('../../plots/plots');
var Lib = require('../../lib');

var attributes = require('./attributes');


module.exports = function(traceIn, traceOut, defaultColor, opts) {
var objName = 'error_' + opts.axis,
containerOut = traceOut[objName] = {},
containerIn = traceIn[objName] || {};

function coerce (attr, dflt) {
return Lib.coerce(containerIn, containerOut, attributes, attr, dflt);
}

var hasErrorBars = (
containerIn.array !== undefined ||
containerIn.value !== undefined ||
containerIn.type === 'sqrt'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

);

var visible = coerce('visible', hasErrorBars);

if(visible === false) return;

var type = coerce('type', 'array' in containerIn ? 'data' : 'percent'),
symmetric = true;

if(type !== 'sqrt') {
symmetric = coerce('symmetric',
!((type === 'data' ? 'arrayminus' : 'valueminus') in containerIn));
}

if(type === 'data') {
var array = coerce('array');
if(!array) containerOut.array = [];
coerce('traceref');
if(!symmetric) {
var arrayminus = coerce('arrayminus');
if(!arrayminus) containerOut.arrayminus = [];
coerce('tracerefminus');
}
}
else if(type==='percent' || type==='constant') {
coerce('value');
if(!symmetric) coerce('valueminus');
}

var copyAttr = 'copy_'+opts.inherit+'style';
if(opts.inherit) {
var inheritObj = traceOut['error_' + opts.inherit];
if((inheritObj||{}).visible) {
coerce(copyAttr, !(containerIn.color ||
isNumeric(containerIn.thickness) ||
isNumeric(containerIn.width)));
}
}
if(!opts.inherit || !containerOut[copyAttr]) {
coerce('color', defaultColor);
coerce('thickness');
coerce('width', Plots.traceIs(traceOut, 'gl3d') ? 0 : 4);
}
};
Loading