Skip to content

Commit e891bac

Browse files
committed
Merge pull request #343 from plotly/error-order
fix error bar trace ordering [fixes #338]
2 parents a27d62c + cf0c211 commit e891bac

File tree

13 files changed

+242
-141
lines changed

13 files changed

+242
-141
lines changed

src/components/errorbars/index.js

+2-124
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@
99

1010
'use strict';
1111

12-
var d3 = require('d3');
13-
var isNumeric = require('fast-isnumeric');
14-
15-
var Lib = require('../../lib');
16-
var Color = require('../color');
17-
var subTypes = require('../../traces/scatter/subtypes');
18-
19-
2012
var errorBars = module.exports = {};
2113

2214
errorBars.attributes = require('./attributes');
@@ -49,123 +41,9 @@ errorBars.calcFromTrace = function(trace, layout) {
4941
return calcdataMock;
5042
};
5143

52-
// the main drawing function for errorbars
53-
errorBars.plot = function(gd, plotinfo, cd) {
54-
// ___ <-- "errorhats"
55-
// |
56-
// | <-- "errorbars"
57-
// |
58-
// ___ <-- "errorshoes"
59-
60-
var xa = plotinfo.x(),
61-
ya = plotinfo.y();
62-
63-
// first remove all existing errorbars
64-
// TODO: use enter/exit instead
65-
plotinfo.plot.select('.errorlayer').selectAll('g.errorbars').remove();
66-
var coords;
67-
68-
// draw the errorbars
69-
plotinfo.plot.select('.errorlayer').selectAll('g.errorbars')
70-
.data(cd)
71-
.enter().append('g')
72-
.attr('class','errorbars')
73-
.each(function(d) {
74-
var trace = d[0].trace,
75-
xObj = trace.error_x,
76-
yObj = trace.error_y,
77-
sparse = subTypes.hasMarkers(trace) &&
78-
trace.marker.maxdisplayed>0;
79-
80-
if(!yObj.visible && !xObj.visible) return;
81-
82-
d3.select(this).selectAll('g')
83-
.data(Lib.identity)
84-
.enter().append('g')
85-
.each(function(d) {
86-
coords = errorcoords(d, xa, ya);
87-
var eb = d3.select(this),
88-
path;
89-
if(sparse && !d.vis) return;
90-
91-
if(yObj.visible && isNumeric(coords.x) &&
92-
isNumeric(coords.yh) &&
93-
isNumeric(coords.ys)) {
94-
var yw = yObj.width;
95-
path = 'M'+(coords.x-yw)+','+coords.yh+'h'+(2*yw) + // hat
96-
'm-'+yw+',0V'+coords.ys; // bar
97-
if(!coords.noYS) path += 'm-'+yw+',0h'+(2*yw); // shoe
98-
99-
eb.append('path')
100-
.classed('yerror', true)
101-
.attr('d', path);
102-
}
103-
if(xObj.visible && isNumeric(coords.y) &&
104-
isNumeric(coords.xh) &&
105-
isNumeric(coords.xs)) {
106-
var xw = (xObj.copy_ystyle ? yObj : xObj).width;
107-
path = 'M'+coords.xh+','+(coords.y-xw)+'v'+(2*xw) + // hat
108-
'm0,-'+xw+'H'+coords.xs; // bar
109-
if(!coords.noXS) path += 'm0,-'+xw+'v'+(2*xw); // shoe
110-
111-
eb.append('path')
112-
.classed('xerror', true)
113-
.attr('d', path);
114-
}
115-
});
116-
});
117-
};
118-
119-
errorBars.style = function(gd) {
120-
d3.select(gd).selectAll('g.errorbars').each(function(d) {
121-
var eb = d3.select(this),
122-
trace = d[0].trace,
123-
yObj = trace.error_y||{},
124-
xObj = trace.error_x||{};
125-
126-
eb.selectAll('g path.yerror')
127-
.style('stroke-width', yObj.thickness+'px')
128-
.call(Color.stroke, yObj.color);
129-
130-
if(xObj.copy_ystyle) xObj = yObj;
131-
132-
eb.selectAll('g path.xerror')
133-
.style('stroke-width', xObj.thickness+'px')
134-
.call(Color.stroke, xObj.color);
135-
});
136-
};
137-
138-
function errorcoords(d, xa, ya) {
139-
// compute the coordinates of the error-bar objects
140-
var out = {
141-
x: xa.c2p(d.x),
142-
y: ya.c2p(d.y)
143-
};
144-
145-
// calculate the error bar size and hat and shoe locations
146-
if(d.yh!==undefined) {
147-
out.yh = ya.c2p(d.yh);
148-
out.ys = ya.c2p(d.ys);
149-
150-
// if the shoes go off-scale (ie log scale, error bars past zero)
151-
// clip the bar and hide the shoes
152-
if(!isNumeric(out.ys)) {
153-
out.noYS = true;
154-
out.ys = ya.c2p(d.ys, true);
155-
}
156-
}
157-
if(d.xh!==undefined) {
158-
out.xh = xa.c2p(d.xh);
159-
out.xs = xa.c2p(d.xs);
160-
161-
if(!isNumeric(out.xs)) {
162-
out.noXS = true;
163-
out.xs = xa.c2p(d.xs, true);
164-
}
165-
}
44+
errorBars.plot = require('./plot');
16645

167-
return out;
168-
}
46+
errorBars.style = require('./style');
16947

17048
errorBars.hoverInfo = function(calcPoint, trace, hoverPoint) {
17149
if(trace.error_y.visible) {

src/components/errorbars/plot.js

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* Copyright 2012-2016, 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 d3 = require('d3');
13+
var isNumeric = require('fast-isnumeric');
14+
15+
var Lib = require('../../lib');
16+
var subTypes = require('../../traces/scatter/subtypes');
17+
18+
19+
module.exports = function plot(traces, plotinfo) {
20+
var xa = plotinfo.x(),
21+
ya = plotinfo.y();
22+
23+
traces.each(function(d) {
24+
var trace = d[0].trace,
25+
xObj = trace.error_x,
26+
yObj = trace.error_y;
27+
28+
var sparse = (
29+
subTypes.hasMarkers(trace) &&
30+
trace.marker.maxdisplayed > 0
31+
);
32+
33+
if(!yObj.visible && !xObj.visible) return;
34+
35+
var errorbars = d3.select(this).selectAll('g.errorbar')
36+
.data(Lib.identity);
37+
38+
errorbars.enter().append('g')
39+
.classed('errorbar', true);
40+
41+
errorbars.each(function(d) {
42+
var errorbar = d3.select(this);
43+
var coords = errorCoords(d, xa, ya);
44+
45+
if(sparse && !d.vis) return;
46+
47+
var path;
48+
49+
if(yObj.visible && isNumeric(coords.x) &&
50+
isNumeric(coords.yh) &&
51+
isNumeric(coords.ys)) {
52+
var yw = yObj.width;
53+
54+
path = 'M' + (coords.x - yw) + ',' +
55+
coords.yh + 'h' + (2 * yw) + // hat
56+
'm-' + yw + ',0V' + coords.ys; // bar
57+
58+
if(!coords.noYS) path += 'm-' + yw +',0h' + (2 * yw); // shoe
59+
60+
errorbar.append('path')
61+
.classed('yerror', true)
62+
.attr('d', path);
63+
}
64+
65+
if(xObj.visible && isNumeric(coords.y) &&
66+
isNumeric(coords.xh) &&
67+
isNumeric(coords.xs)) {
68+
var xw = (xObj.copy_ystyle ? yObj : xObj).width;
69+
70+
path = 'M' + coords.xh + ',' +
71+
(coords.y - xw) + 'v' + (2 * xw) + // hat
72+
'm0,-' + xw + 'H' + coords.xs; // bar
73+
74+
if(!coords.noXS) path += 'm0,-' + xw + 'v' + (2 * xw); // shoe
75+
76+
errorbar.append('path')
77+
.classed('xerror', true)
78+
.attr('d', path);
79+
}
80+
});
81+
});
82+
};
83+
84+
// compute the coordinates of the error-bar objects
85+
function errorCoords(d, xa, ya) {
86+
var out = {
87+
x: xa.c2p(d.x),
88+
y: ya.c2p(d.y)
89+
};
90+
91+
// calculate the error bar size and hat and shoe locations
92+
if(d.yh !== undefined) {
93+
out.yh = ya.c2p(d.yh);
94+
out.ys = ya.c2p(d.ys);
95+
96+
// if the shoes go off-scale (ie log scale, error bars past zero)
97+
// clip the bar and hide the shoes
98+
if(!isNumeric(out.ys)) {
99+
out.noYS = true;
100+
out.ys = ya.c2p(d.ys, true);
101+
}
102+
}
103+
104+
if(d.xh !== undefined) {
105+
out.xh = xa.c2p(d.xh);
106+
out.xs = xa.c2p(d.xs);
107+
108+
if(!isNumeric(out.xs)) {
109+
out.noXS = true;
110+
out.xs = xa.c2p(d.xs, true);
111+
}
112+
}
113+
114+
return out;
115+
}

src/components/errorbars/style.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Copyright 2012-2016, 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 d3 = require('d3');
13+
14+
var Color = require('../color');
15+
16+
17+
module.exports = function style(traces) {
18+
traces.each(function(d) {
19+
var trace = d[0].trace,
20+
yObj = trace.error_y || {},
21+
xObj = trace.error_x || {};
22+
23+
var s = d3.select(this);
24+
25+
s.selectAll('path.yerror')
26+
.style('stroke-width', yObj.thickness + 'px')
27+
.call(Color.stroke, yObj.color);
28+
29+
if(xObj.copy_ystyle) xObj = yObj;
30+
31+
s.selectAll('path.xerror')
32+
.style('stroke-width', xObj.thickness + 'px')
33+
.call(Color.stroke, xObj.color);
34+
});
35+
};

src/plot_api/plot_api.js

-1
Original file line numberDiff line numberDiff line change
@@ -2672,7 +2672,6 @@ function makeCartesianPlotFramwork(gd, subplots) {
26722672
svg.append('g').classed('imagelayer', true);
26732673
svg.append('g').classed('maplayer', true);
26742674
svg.append('g').classed('barlayer', true);
2675-
svg.append('g').classed('errorlayer', true);
26762675
svg.append('g').classed('boxlayer', true);
26772676
svg.append('g').classed('scatterlayer', true);
26782677
}

src/plots/cartesian/index.js

+2-13
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
var Lib = require('../../lib');
1313
var Plots = require('../plots');
14-
var ErrorBars = require('../../components/errorbars');
15-
1614

1715
exports.name = 'cartesian';
1816

@@ -71,8 +69,7 @@ exports.plot = function(gd) {
7169
for(var i = 0; i < subplots.length; i++) {
7270
var subplot = subplots[i],
7371
subplotInfo = fullLayout._plots[subplot],
74-
cdSubplot = getCdSubplot(calcdata, subplot),
75-
cdError = [];
72+
cdSubplot = getCdSubplot(calcdata, subplot);
7673

7774
// remove old traces, then redraw everything
7875
// TODO: use enter/exit appropriately in the plot functions
@@ -91,17 +88,9 @@ exports.plot = function(gd) {
9188
// plot all traces of this type on this subplot at once
9289
var cdModule = getCdModule(cdSubplot, _module);
9390
_module.plot(gd, subplotInfo, cdModule);
94-
Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type));
9591

96-
// collect the traces that may have error bars
97-
if(cdModule[0] && cdModule[0][0].trace && Plots.traceIs(cdModule[0][0].trace, 'errorBarsOK')) {
98-
cdError = cdError.concat(cdModule);
99-
}
92+
Lib.markTime('done ' + (cdModule[0] && cdModule[0][0].trace.type));
10093
}
101-
102-
// finally do all error bars at once
103-
ErrorBars.plot(gd, subplotInfo, cdError);
104-
Lib.markTime('done ErrorBars');
10594
}
10695

10796
// now draw stuff not on subplots (ie, only pies at the moment)

src/plots/plots.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -805,10 +805,11 @@ plots.purge = function(gd) {
805805
};
806806

807807
plots.style = function(gd) {
808-
var modulesWithErrorBars = gd._modules.concat(Plotly.ErrorBars);
808+
var _modules = gd._modules;
809+
810+
for(var i = 0; i < _modules.length; i++) {
811+
var _module = _modules[i];
809812

810-
for(var i = 0; i < modulesWithErrorBars.length; i++) {
811-
var _module = modulesWithErrorBars[i];
812813
if(_module.style) _module.style(gd);
813814
}
814815
};

src/traces/bar/plot.js

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var isNumeric = require('fast-isnumeric');
1414

1515
var Lib = require('../../lib');
1616
var Color = require('../../components/color');
17+
var ErrorBars = require('../../components/errorbars');
1718

1819
var arraysToCalcdata = require('./arrays_to_calcdata');
1920

@@ -102,4 +103,8 @@ module.exports = function plot(gd, plotinfo, cdbar) {
102103
'M'+x0+','+y0+'V'+y1+'H'+x1+'V'+y0+'Z');
103104
});
104105
});
106+
107+
// error bars are on the top
108+
bartraces.call(ErrorBars.plot, plotinfo);
109+
105110
};

src/traces/bar/style.js

+3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var d3 = require('d3');
1313

1414
var Color = require('../../components/color');
1515
var Drawing = require('../../components/drawing');
16+
var ErrorBars = require('../../components/errorbars');
1617

1718

1819
module.exports = function style(gd) {
@@ -71,4 +72,6 @@ module.exports = function style(gd) {
7172
// d3.select(this).selectAll('text')
7273
// .call(Plotly.Drawing.textPointStyle,d.t||d[0].t);
7374
});
75+
76+
s.call(ErrorBars.style);
7477
};

0 commit comments

Comments
 (0)