Skip to content

Commit 8f89564

Browse files
committed
started waterfall
1 parent 02e51d8 commit 8f89564

File tree

78 files changed

+4765
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+4765
-20
lines changed

lib/index.js

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Plotly.register([
2222
require('./contour'),
2323
require('./scatterternary'),
2424
require('./violin'),
25+
require('./waterfall'),
2526

2627
require('./scatter3d'),
2728
require('./surface'),

lib/waterfall.js

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* Copyright 2012-2019, 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+
module.exports = require('../src/traces/waterfall');

src/components/drawing/index.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ drawing.hideOutsideRangePoints = function(traceGroups, subplot) {
110110
var trace = d[0].trace;
111111
var xcalendar = trace.xcalendar;
112112
var ycalendar = trace.ycalendar;
113-
var selector = trace.type === 'bar' ? '.bartext' : '.point,.textpoint';
113+
var selector = (
114+
trace.type === 'bar' ||
115+
trace.type === 'waterfall') ?
116+
'.bartext' : '.point,.textpoint';
114117

115118
traceGroups.selectAll(selector).each(function(d) {
116119
drawing.hideOutsideRangePoint(d, d3.select(this), xa, ya, xcalendar, ycalendar);

src/components/legend/defaults.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@ module.exports = function legendDefaults(layoutIn, layoutOut, fullData) {
5050
}
5151
}
5252

53-
if((Registry.traceIs(trace, 'bar') && layoutOut.barmode === 'stack') ||
53+
if(((Registry.traceIs(trace, 'bar') ||
54+
Registry.traceIs(trace, 'waterfall')) &&
55+
layoutOut.barmode === 'stack') ||
5456
['tonextx', 'tonexty'].indexOf(trace.fill) !== -1) {
5557
defaultOrder = helpers.isGrouped({traceorder: defaultOrder}) ?
5658
'grouped+reversed' : 'reversed';

src/components/legend/style.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,10 @@ module.exports = function style(s, gd) {
248248

249249
var barpath = d3.select(this).select('g.legendpoints')
250250
.selectAll('path.legendbar')
251-
.data(Registry.traceIs(trace, 'bar') ? [d] : []);
251+
.data((
252+
Registry.traceIs(trace, 'bar') ||
253+
Registry.traceIs(trace, 'waterfall')
254+
) ? [d] : []);
252255
barpath.enter().append('path').classed('legendbar', true)
253256
.attr('d', 'M6,6H-6V-6H6Z')
254257
.attr('transform', 'translate(20,0)');

src/plot_api/helpers.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ exports.cleanData = function(data) {
290290
// error_y.opacity is obsolete - merge into color
291291
if(trace.error_y && 'opacity' in trace.error_y) {
292292
var dc = Color.defaults;
293-
var yeColor = trace.error_y.color || (Registry.traceIs(trace, 'bar') ?
293+
var yeColor = trace.error_y.color ||
294+
((Registry.traceIs(trace, 'bar') ||
295+
Registry.traceIs(trace, 'waterfall')) ?
294296
Color.defaultLine :
295297
dc[tracei % dc.length]);
296298
trace.error_y.color = Color.addOpacity(
@@ -302,8 +304,10 @@ exports.cleanData = function(data) {
302304
// convert bardir to orientation, and put the data into
303305
// the axes it's eventually going to be used with
304306
if('bardir' in trace) {
305-
if(trace.bardir === 'h' && (Registry.traceIs(trace, 'bar') ||
306-
trace.type.substr(0, 9) === 'histogram')) {
307+
if(trace.bardir === 'h' &&
308+
((Registry.traceIs(trace, 'bar') ||
309+
Registry.traceIs(trace, 'waterfall')) ||
310+
trace.type.substr(0, 9) === 'histogram')) {
307311
trace.orientation = 'h';
308312
exports.swapXYData(trace);
309313
}
@@ -336,7 +340,9 @@ exports.cleanData = function(data) {
336340
trace.scene = Plots.subplotsRegistry.gl3d.cleanId(trace.scene);
337341
}
338342

339-
if(!Registry.traceIs(trace, 'pie') && !Registry.traceIs(trace, 'bar')) {
343+
if(!Registry.traceIs(trace, 'pie') &&
344+
!Registry.traceIs(trace, 'bar') &&
345+
!Registry.traceIs(trace, 'waterfall')) {
340346
if(Array.isArray(trace.textposition)) {
341347
for(i = 0; i < trace.textposition.length; i++) {
342348
trace.textposition[i] = cleanTextPosition(trace.textposition[i]);

src/plot_api/plot_api.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -1670,7 +1670,11 @@ function _restyle(gd, aobj, traces) {
16701670
else if(ai === 'type' && (newVal === 'pie') !== (oldVal === 'pie')) {
16711671
var labelsTo = 'x';
16721672
var valuesTo = 'y';
1673-
if((newVal === 'bar' || oldVal === 'bar') && cont.orientation === 'h') {
1673+
if(cont.orientation === 'h' && (
1674+
newVal === 'bar' ||
1675+
oldVal === 'bar' ||
1676+
newVal === 'waterfall' ||
1677+
oldVal === 'waterfall')) {
16741678
labelsTo = 'y';
16751679
valuesTo = 'x';
16761680
}

src/plots/cartesian/axes.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -2822,7 +2822,9 @@ function hasBarsOrFill(gd, ax) {
28222822
if(trace.visible === true &&
28232823
(trace.xaxis + trace.yaxis) === subplot &&
28242824
(
2825-
Registry.traceIs(trace, 'bar') && trace.orientation === {x: 'h', y: 'v'}[axLetter] ||
2825+
(Registry.traceIs(trace, 'bar') ||
2826+
Registry.traceIs(trace, 'waterfall')) &&
2827+
trace.orientation === {x: 'h', y: 'v'}[axLetter] ||
28262828
trace.fill && trace.fill.charAt(trace.fill.length - 1) === axLetter
28272829
)
28282830
) {

src/traces/bar/calc.js

+22-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ var calcSelection = require('../scatter/calc_selection');
1717
module.exports = function calc(gd, trace) {
1818
var xa = Axes.getFromId(gd, trace.xaxis || 'x');
1919
var ya = Axes.getFromId(gd, trace.yaxis || 'y');
20-
var size, pos;
20+
var size, pos, i;
21+
22+
var isWaterfall = (trace.type === 'waterfall');
2123

2224
if(trace.orientation === 'h') {
2325
size = xa.makeCalcdata(trace, 'x');
@@ -31,9 +33,25 @@ module.exports = function calc(gd, trace) {
3133
var serieslen = Math.min(pos.length, size.length);
3234
var cd = new Array(serieslen);
3335

34-
// set position and size
35-
for(var i = 0; i < serieslen; i++) {
36-
cd[i] = { p: pos[i], s: size[i] };
36+
// set position and size (as well as for waterfall total size)
37+
var previousSum = 0;
38+
for(i = 0; i < serieslen; i++) {
39+
cd[i] = {
40+
p: pos[i],
41+
s: size[i]
42+
};
43+
44+
if(isWaterfall) {
45+
if(cd[i].s === undefined) {
46+
cd[i].isFall = true;
47+
cd[i].s = previousSum;
48+
} else {
49+
cd[i].isFall = false;
50+
var newSize = cd[i].s;
51+
cd[i].s += previousSum;
52+
previousSum += newSize;
53+
}
54+
}
3755

3856
if(trace.ids) {
3957
cd[i].id = String(trace.ids[i]);

src/traces/bar/cross_trace_calc.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ function crossTraceCalc(gd, plotinfo) {
3636
var fullTrace = fullTraces[i];
3737
if(
3838
fullTrace.visible === true &&
39-
Registry.traceIs(fullTrace, 'bar') &&
39+
(Registry.traceIs(fullTrace, 'bar') ||
40+
Registry.traceIs(fullTrace, 'waterfall')) &&
4041
fullTrace.xaxis === xa._id &&
4142
fullTrace.yaxis === ya._id
4243
) {
@@ -646,6 +647,8 @@ function collectExtents(calcTraces, pa) {
646647
cd = calcTraces[i];
647648
cd[0].t.extents = extents;
648649

650+
var isWaterfall = (cd[0].trace.type === 'waterfall');
651+
649652
var poffset = cd[0].t.poffset;
650653
var poffsetIsArray = Array.isArray(poffset);
651654

@@ -667,6 +670,12 @@ function collectExtents(calcTraces, pa) {
667670
di.p1 = di.p0 + di.w;
668671
di.s0 = di.b;
669672
di.s1 = di.s0 + di.s;
673+
674+
if(isWaterfall) {
675+
if(di.isFall === false) {
676+
di.s0 += (j === 0) ? 0 : cd[j - 1].s;
677+
}
678+
}
670679
}
671680
}
672681
}

src/traces/bar/defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var Color = require('../../components/color');
1414
var Registry = require('../../registry');
1515

1616
var handleXYDefaults = require('../scatter/xy_defaults');
17-
var handleStyleDefaults = require('../bar/style_defaults');
17+
var handleStyleDefaults = require('./style_defaults');
1818
var attributes = require('./attributes');
1919

2020
module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout) {

src/traces/bar/hover.js

+3
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ function hoverPoints(pointData, xval, yval, hovermode) {
120120

121121
var size = (trace.base) ? di.b + di.s : di.s;
122122
pointData[sizeLetter + '0'] = pointData[sizeLetter + '1'] = sa.c2p(di[sizeLetter], true);
123+
if(trace.type === 'waterfall' && di.isFall === false) {
124+
size -= (index === 0) ? 0 : cd[index - 1].s;
125+
}
123126
pointData[sizeLetter + 'LabelVal'] = size;
124127

125128
var extent = t.extents[t.extents.round(di.p)];

src/traces/bar/layout_defaults.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ module.exports = function(layoutIn, layoutOut, fullData) {
2828

2929
for(var i = 0; i < fullData.length; i++) {
3030
var trace = fullData[i];
31-
if(Registry.traceIs(trace, 'bar') && trace.visible) hasBars = true;
31+
if((Registry.traceIs(trace, 'bar') ||
32+
Registry.traceIs(trace, 'waterfall')) &&
33+
trace.visible) hasBars = true;
3234
else continue;
3335

3436
// if we have at least 2 grouped bar traces on the same subplot,

src/traces/bar/plot.js

+19-4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ module.exports = function plot(gd, plotinfo, cdbar, barLayer) {
3838
var cd0 = cd[0];
3939
var trace = cd0.trace;
4040

41+
var isWaterfall = (trace.type === 'waterfall');
42+
var isTriangle = (isWaterfall) ? (trace.marker.shape === 'triangle') : false;
43+
var isVertical = (trace.orientation === 'v');
44+
4145
if(!plotinfo.isRangePlot) cd0.node3 = plotGroup;
4246

4347
var pointGroup = Lib.ensureSingle(plotGroup, 'g', 'points');
@@ -111,6 +115,7 @@ module.exports = function plot(gd, plotinfo, cdbar, barLayer) {
111115
// pixelation. if the bars ARE fully opaque and have
112116
// no line, expand to a full pixel to make sure we
113117
// can see them
118+
114119
var op = Color.opacity(di.mc || trace.marker.color);
115120
var fixpx = (op < 1 || lw > 0.01) ? roundWithLine : expandToVisible;
116121
x0 = fixpx(x0, x1);
@@ -119,11 +124,21 @@ module.exports = function plot(gd, plotinfo, cdbar, barLayer) {
119124
y1 = fixpx(y1, y0);
120125
}
121126

127+
var shape;
128+
if(isWaterfall && isTriangle && i > 0 && cd[i].isFall === false) {
129+
if(isVertical) {
130+
shape = 'M' + x0 + ',' + y0 + 'L' + (0.5 * (x1 + x0)) + ',' + y1 + 'L' + x1 + ',' + y0 + 'Z';
131+
} else {
132+
shape = 'M' + x0 + ',' + y0 + 'L' + x1 + ',' + (0.5 * (y1 + y0)) + 'L' + x0 + ',' + y1 + 'Z';
133+
}
134+
} else {
135+
shape = 'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z';
136+
}
137+
122138
Lib.ensureSingle(bar, 'path')
123-
.style('vector-effect', 'non-scaling-stroke')
124-
.attr('d',
125-
'M' + x0 + ',' + y0 + 'V' + y1 + 'H' + x1 + 'V' + y0 + 'Z')
126-
.call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
139+
.style('vector-effect', 'non-scaling-stroke')
140+
.attr('d', shape)
141+
.call(Drawing.setClipUrl, plotinfo.layerClipId, gd);
127142

128143
appendBarText(gd, bar, cd, i, x0, x1, y0, y1);
129144

src/traces/waterfall/attributes.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright 2012-2019, 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 extendFlat = require('../../lib/extend').extendFlat;
12+
13+
var barAttrs = require('../bar/attributes');
14+
15+
module.exports = {
16+
17+
x: barAttrs.x,
18+
x0: barAttrs.x0,
19+
dx: barAttrs.dx,
20+
y: barAttrs.y,
21+
y0: barAttrs.y0,
22+
dy: barAttrs.dy,
23+
24+
r: barAttrs.r,
25+
t: barAttrs.t,
26+
27+
text: barAttrs.text,
28+
hovertext: barAttrs.hovertext,
29+
hovertemplate: barAttrs.hovertemplate,
30+
31+
textposition: barAttrs.textposition,
32+
33+
textfont: barAttrs.textfont,
34+
35+
insidetextfont: barAttrs.insidetextfont,
36+
37+
outsidetextfont: barAttrs.outsidetextfont,
38+
39+
constraintext: barAttrs.constraintext,
40+
41+
cliponaxis: barAttrs.cliponaxis,
42+
43+
orientation: barAttrs.orientation,
44+
45+
base: barAttrs.base,
46+
47+
offset: barAttrs.offset,
48+
49+
width: barAttrs.width,
50+
51+
marker: extendFlat({}, barAttrs.marker, {
52+
shape: {
53+
valType: 'enumerated',
54+
values: ['rectangle', 'triangle'],
55+
dflt: 'rectangle',
56+
role: 'style',
57+
editType: 'style',
58+
description: [
59+
'Defines the shape of positive/negative bars on the plot.',
60+
'Namely \'triangle`\ option could be used to emphasize on',
61+
'the direction of the changes.'
62+
].join(' ')
63+
}
64+
}),
65+
66+
selected: barAttrs.selected,
67+
unselected: barAttrs.unselected
68+
};

0 commit comments

Comments
 (0)