diff --git a/devtools/image_viewer/viewer.js b/devtools/image_viewer/viewer.js index 3a38a5cf36f..5b1d8e4fbca 100644 --- a/devtools/image_viewer/viewer.js +++ b/devtools/image_viewer/viewer.js @@ -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( diff --git a/src/components/errorbars/calc.js b/src/components/errorbars/calc.js new file mode 100644 index 00000000000..5f732c20e8f --- /dev/null +++ b/src/components/errorbars/calc.js @@ -0,0 +1,61 @@ +/** +* 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 xa = Axes.getFromId(gd, trace.xaxis), + ya = Axes.getFromId(gd, trace.yaxis); + + calcOneAxis(calcTrace, trace, xa, 'x'); + calcOneAxis(calcTrace, trace, ya, 'y'); + } +}; + +function calcOneAxis(calcTrace, trace, axis, coord) { + var opts = trace['error_' + coord] || {}, + isVisible = (opts.visible && ['linear', 'log'].indexOf(axis.type) !== -1), + vals = []; + + if(!isVisible) return; + + var computeError = makeComputeError(opts); + + for(var i = 0; i < calcTrace.length; i++) { + var calcPt = calcTrace[i], + calcCoord = calcPt[coord]; + + if(!isNumeric(axis.c2l(calcCoord))) continue; + + var errors = computeError(calcCoord, i); + if(isNumeric(errors[0]) && isNumeric(errors[1])) { + var shoe = calcPt[coord + 's'] = calcCoord - errors[0], + hat = calcPt[coord + 'h'] = calcCoord + errors[1]; + vals.push(shoe, hat); + } + } + + Axes.expand(axis, vals, {padded: true}); +} diff --git a/src/components/errorbars/compute_error.js b/src/components/errorbars/compute_error.js new file mode 100644 index 00000000000..601bb76f781 --- /dev/null +++ b/src/components/errorbars/compute_error.js @@ -0,0 +1,94 @@ +/** +* 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. The generated function does not clean the dataPt entries. Non-numeric + * entries result in undefined error magnitudes. + * + * @param {object} opts error bar attributes + * + * @return {function} : + * @param {numeric} dataPt data point from where to compute the error magnitude + * @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) { + return [+arrayminus[index], +array[index]]; + }; + } + } + else { + var computeErrorValue = makeComputeErrorValue(type, opts.value), + computeErrorValueMinus = makeComputeErrorValue(type, opts.valueminus); + + if(symmetric || opts.valueminus === undefined) { + return function computeError(dataPt) { + var val = computeErrorValue(dataPt); + return [val, val]; + }; + } + else { + return function computeError(dataPt) { + return [ + computeErrorValueMinus(dataPt), + computeErrorValue(dataPt) + ]; + }; + } + } +}; + +/** + * Compute error bar magnitude (for all types except data) + * + * @param {string} type error bar type + * @param {numeric} value error bar value + * + * @return {function} : + * @param {numeric} dataPt + */ +function makeComputeErrorValue(type, value) { + if(type === 'percent') { + return function(dataPt) { + return Math.abs(dataPt * value / 100); + }; + } + if(type === 'constant') { + return function() { + return Math.abs(value); + }; + } + if(type === 'sqrt') { + return function(dataPt) { + return Math.sqrt(Math.abs(dataPt)); + }; + } +} diff --git a/src/components/errorbars/defaults.js b/src/components/errorbars/defaults.js new file mode 100644 index 00000000000..cf5a48a322d --- /dev/null +++ b/src/components/errorbars/defaults.js @@ -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' + ); + + 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); + } +}; diff --git a/src/components/errorbars/index.js b/src/components/errorbars/index.js index 6575e8ef84f..b04bfaad4a9 100644 --- a/src/components/errorbars/index.js +++ b/src/components/errorbars/index.js @@ -17,165 +17,9 @@ var errorBars = module.exports = {}; errorBars.attributes = require('./attributes'); -errorBars.supplyDefaults = function(traceIn, traceOut, defaultColor, opts) { - var objName = 'error_' + opts.axis, - containerOut = traceOut[objName] = {}, - containerIn = traceIn[objName] || {}; +errorBars.supplyDefaults = require('./defaults'); - function coerce (attr, dflt) { - return Plotly.Lib.coerce(containerIn, containerOut, errorBars.attributes, attr, dflt); - } - - var visible = coerce('visible', 'array' in containerIn || 'value' in containerIn); - if(visible) { - 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', Plotly.Plots.traceIs(traceOut, 'gl3d') ? 0 : 4); - } - } -}; - -errorBars.pushRef2GDC = function(gd, selCurve, astr, val){ - // Copy the error bar data into gdc - // This is called from the style-box, where - // either the reference trace was selected. - // This function copies the data from the referenced trace - // into the gdc object - // selCurve: the selected curve (i.e. gdc = gd[selCurve]) - // astr: the string that was modified - var iRef, - various = false, - parts = astr.split('.'), - container = parts[0], - attr = parts[1], - letter = container.charAt(container.length-1); - if(attr==='type'){ - if(selCurve==='various'){ - various = true; - selCurve = 0; - } - // if the 'trace' type was just selected - iRef = Number(gd.calcdata[Number(selCurve)][0].trace['error_' + letter].traceref)||0; - } - else if(attr==='traceref' || attr==='tracerefminus'){ - if(selCurve==='various') various = true; - // if the trace reference was just modified - iRef = Number(val)||0; - } - - // now copy the appropriate referenced error bar data into gdc - // TODO: do this through restyle so we can undo it - // the error bar data that we're referencing - var newdata = gd.data[iRef][letter].map(Number); - - function setarrays(i) { - var eb = gd.data[i][container]; - eb[attr==='tracerefminus' ? 'arrayminus' : 'array'] = newdata; - } - - if(!various) setarrays(Number(selCurve)); - else{ - // copy all of the data - // TODO: this won't work right if we just select some traces, right? - for(var i=0; i