Skip to content

scattergl errorbars fixes #2620

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 2 additions & 27 deletions src/components/errorbars/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ var Lib = require('../../lib');
var overrideAll = require('../../plot_api/edit_types').overrideAll;

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

var xyAttrs = {
error_x: Lib.extendFlat({}, attributes),
Expand Down Expand Up @@ -48,38 +47,14 @@ module.exports = {

supplyDefaults: require('./defaults'),

calc: calc,
calcFromTrace: calcFromTrace,
calc: require('./calc'),
makeComputeError: require('./compute_error'),

plot: require('./plot'),
style: require('./style'),
hoverInfo: hoverInfo
};

function calcFromTrace(trace, layout) {
var x = trace.x || [],
y = trace.y || [],
len = x.length || y.length;

var calcdataMock = new Array(len);

for(var i = 0; i < len; i++) {
calcdataMock[i] = {
x: x[i],
y: y[i]
};
}

calcdataMock[0].trace = trace;

calc({
calcdata: [calcdataMock],
_fullLayout: layout
});

return calcdataMock;
}

function hoverInfo(calcPoint, trace, hoverPoint) {
if((trace.error_y || {}).visible) {
hoverPoint.yerr = calcPoint.yh - calcPoint.y;
Expand Down
5 changes: 2 additions & 3 deletions src/traces/scatter3d/calc_errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
* LICENSE file in the root directory of this source tree.
*/


'use strict';

var makeComputeError = require('../../components/errorbars/compute_error');
var Registry = require('../../registry');

function calculateAxisErrors(data, params, scaleFactor) {
if(!params || !params.visible) return null;

var computeError = makeComputeError(params);
var computeError = Registry.getComponentMethod('errorbars', 'makeComputeError')(params);
var result = new Array(data.length);

for(var i = 0; i < data.length; i++) {
Expand Down
78 changes: 49 additions & 29 deletions src/traces/scattergl/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

'use strict';

var isNumeric = require('fast-isnumeric');
var svgSdf = require('svg-path-sdf');
var rgba = require('color-normalize');

var Registry = require('../../registry');
var Lib = require('../../lib');
var Drawing = require('../../components/drawing');
var Axes = require('../../plots/cartesian/axes');
var AxisIDs = require('../../plots/cartesian/axis_ids');

var formatColor = require('../../lib/gl_format_color').formatColor;
Expand Down Expand Up @@ -360,42 +362,60 @@ function convertLinePositions(gd, trace, positions) {
};
}

function convertErrorBarPositions(gd, trace, positions) {
var calcFromTrace = Registry.getComponentMethod('errorbars', 'calcFromTrace');
var vals = calcFromTrace(trace, gd._fullLayout);
function convertErrorBarPositions(gd, trace, positions, x, y) {
var makeComputeError = Registry.getComponentMethod('errorbars', 'makeComputeError');
var xa = AxisIDs.getFromId(gd, trace.xaxis);
var ya = AxisIDs.getFromId(gd, trace.yaxis);
var count = positions.length / 2;
var out = {};

function put(axLetter) {
var errors = new Float64Array(4 * count);
var ax = AxisIDs.getFromId(gd, trace[axLetter + 'axis']);
var pOffset = {x: 0, y: 1}[axLetter];
var eOffset = {x: [0, 1, 2, 3], y: [2, 3, 0, 1]}[axLetter];

for(var i = 0, p = 0; i < count; i++, p += 4) {
errors[p + eOffset[0]] = positions[i * 2 + pOffset] - ax.d2l(vals[i][axLetter + 's']) || 0;
errors[p + eOffset[1]] = ax.d2l(vals[i][axLetter + 'h']) - positions[i * 2 + pOffset] || 0;
errors[p + eOffset[2]] = 0;
errors[p + eOffset[3]] = 0;
}

return errors;
}
function convertOneAxis(coords, ax) {
var axLetter = ax._id.charAt(0);
var opts = trace['error_' + axLetter];

if(opts && opts.visible && (ax.type === 'linear' || ax.type === 'log')) {
var computeError = makeComputeError(opts);
var pOffset = {x: 0, y: 1}[axLetter];
var eOffset = {x: [0, 1, 2, 3], y: [2, 3, 0, 1]}[axLetter];
var errors = new Float64Array(4 * count);
var minShoe = Infinity;
var maxHat = -Infinity;

for(var i = 0, j = 0; i < count; i++, j += 4) {
var dc = coords[i];

if(isNumeric(dc)) {
var dl = positions[i * 2 + pOffset];
var vals = computeError(dc, i);
var lv = vals[0];
var hv = vals[1];

if(isNumeric(lv) && isNumeric(hv)) {
var shoe = dc - lv;
var hat = dc + hv;

errors[j + eOffset[0]] = dl - ax.c2l(shoe);
errors[j + eOffset[1]] = ax.c2l(hat) - dl;
errors[j + eOffset[2]] = 0;
errors[j + eOffset[3]] = 0;

minShoe = Math.min(minShoe, dc - lv);
maxHat = Math.max(maxHat, dc + hv);
}
}
}

Axes.expand(ax, [minShoe, maxHat], {padded: true});

if(trace.error_x && trace.error_x.visible) {
out.x = {
positions: positions,
errors: put('x')
};
}
if(trace.error_y && trace.error_y.visible) {
out.y = {
positions: positions,
errors: put('y')
};
out[axLetter] = {
positions: positions,
errors: errors
};
}
}

convertOneAxis(x, xa);
convertOneAxis(y, ya);
return out;
}

Expand Down
6 changes: 3 additions & 3 deletions src/traces/scattergl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ function calc(gd, trace) {

// create scene options and scene
calcColorscales(trace);
var opts = sceneOptions(gd, subplot, trace, positions);
var opts = sceneOptions(gd, subplot, trace, positions, x, y);
var scene = sceneUpdate(gd, subplot);

// Re-use SVG scatter axis expansion routine except
Expand Down Expand Up @@ -133,7 +133,7 @@ function calc(gd, trace) {
}

// create scene options
function sceneOptions(gd, subplot, trace, positions) {
function sceneOptions(gd, subplot, trace, positions, x, y) {
var opts = convertStyle(gd, trace);

if(opts.marker) {
Expand All @@ -148,7 +148,7 @@ function sceneOptions(gd, subplot, trace, positions) {
}

if(opts.errorX || opts.errorY) {
var errors = convertErrorBarPositions(gd, trace, positions);
var errors = convertErrorBarPositions(gd, trace, positions, x, y);

if(opts.errorX) {
Lib.extendFlat(opts.errorX, errors.x);
Expand Down
Binary file modified test/image/baselines/gl2d_error_bars.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/image/baselines/gl2d_error_bars_log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions test/image/mocks/gl2d_error_bars.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
{
"data": [
{
"x": [6],
"y": ["2"],
"error_y": {
"type": "data",
"array": [2],
"arrayminus": [4]
},
"type": "scattergl"
},
{
"x": [
0,
Expand Down Expand Up @@ -92,6 +102,19 @@
"value": 10
},
"type": "scattergl"
},
{
"y": [
3,
3,
6,
5
],
"error_x": {
"type": "constant",
"value": 0.1
},
"type": "scattergl"
}
]
}
10 changes: 9 additions & 1 deletion test/image/mocks/gl2d_error_bars_log.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
{
"data": [{
"name": "array error bars",
"type": "scattergl",
"y": [10, 2e4, 5e6],
"error_y": {"array": [5, 1e4, 4e6]}
}, {
"name": "50% percent error bars",
"type": "scattergl",
"x0": 0.2,
"y": [10, 2e4, 5e6],
"error_y": {"type": "percent", "value": 50}
}],
"layout": {
"yaxis": {"type": "log"}
"yaxis": {"type": "log"},
"showlegend": false
}
}