Skip to content

Commit 978303e

Browse files
authored
Merge pull request #3531 from plotly/waterfall-new-trace
Waterfall charts
2 parents c740e3f + 1d275f5 commit 978303e

Some content is hidden

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

60 files changed

+3862
-110
lines changed

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Plotly.register([
2121
require('./contour'),
2222
require('./scatterternary'),
2323
require('./violin'),
24+
require('./waterfall'),
2425

2526
require('./pie'),
2627
require('./sunburst'),

lib/waterfall.js

Lines changed: 11 additions & 0 deletions
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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ 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 = trace.type === 'bar' ? '.bartext' :
114+
trace.type === 'waterfall' ? '.bartext,.line' :
115+
'.point,.textpoint';
114116

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

src/components/legend/style.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ module.exports = function style(s, gd) {
6161
.enter().append('g')
6262
.classed('legendpoints', true);
6363
})
64+
.each(styleWaterfalls)
6465
.each(styleBars)
6566
.each(styleBoxes)
6667
.each(stylePies)
@@ -241,6 +242,38 @@ module.exports = function style(s, gd) {
241242
txt.selectAll('text').call(Drawing.textPointStyle, tMod, gd);
242243
}
243244

245+
function styleWaterfalls(d) {
246+
var trace = d[0].trace;
247+
248+
var ptsData = [];
249+
if(trace.type === 'waterfall' && trace.visible) {
250+
ptsData = d[0].hasTotals ?
251+
[['increasing', 'M-6,-6V6H0Z'], ['totals', 'M6,6H0L-6,-6H-0Z'], ['decreasing', 'M6,6V-6H0Z']] :
252+
[['increasing', 'M-6,-6V6H6Z'], ['decreasing', 'M6,6V-6H-6Z']];
253+
}
254+
255+
var pts = d3.select(this).select('g.legendpoints')
256+
.selectAll('path.legendwaterfall')
257+
.data(ptsData);
258+
pts.enter().append('path').classed('legendwaterfall', true)
259+
.attr('transform', 'translate(20,0)')
260+
.style('stroke-miterlimit', 1);
261+
pts.exit().remove();
262+
263+
pts.each(function(dd) {
264+
var pt = d3.select(this);
265+
var cont = trace[dd[0]].marker;
266+
267+
pt.attr('d', dd[1])
268+
.style('stroke-width', cont.line.width + 'px')
269+
.call(Color.fill, cont.color);
270+
271+
if(cont.line.width) {
272+
pt.call(Color.stroke, cont.line.color);
273+
}
274+
});
275+
}
276+
244277
function styleBars(d) {
245278
var trace = d[0].trace;
246279
var marker = trace.marker || {};

src/plot_api/helpers.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ var Registry = require('../registry');
1616
var Lib = require('../lib');
1717
var Plots = require('../plots/plots');
1818
var AxisIds = require('../plots/cartesian/axis_ids');
19-
var cleanId = AxisIds.cleanId;
20-
var getFromTrace = AxisIds.getFromTrace;
2119
var Color = require('../components/color');
2220

21+
var cleanId = AxisIds.cleanId;
22+
var getFromTrace = AxisIds.getFromTrace;
23+
var traceIs = Registry.traceIs;
2324

2425
// clear the promise queue if one of them got rejected
2526
exports.clearPromiseQueue = function(gd) {
@@ -290,7 +291,7 @@ exports.cleanData = function(data) {
290291
// error_y.opacity is obsolete - merge into color
291292
if(trace.error_y && 'opacity' in trace.error_y) {
292293
var dc = Color.defaults;
293-
var yeColor = trace.error_y.color || (Registry.traceIs(trace, 'bar') ?
294+
var yeColor = trace.error_y.color || (traceIs(trace, 'bar') ?
294295
Color.defaultLine :
295296
dc[tracei % dc.length]);
296297
trace.error_y.color = Color.addOpacity(
@@ -302,8 +303,8 @@ exports.cleanData = function(data) {
302303
// convert bardir to orientation, and put the data into
303304
// the axes it's eventually going to be used with
304305
if('bardir' in trace) {
305-
if(trace.bardir === 'h' && (Registry.traceIs(trace, 'bar') ||
306-
trace.type.substr(0, 9) === 'histogram')) {
306+
if(trace.bardir === 'h' && (traceIs(trace, 'bar') ||
307+
trace.type.substr(0, 9) === 'histogram')) {
307308
trace.orientation = 'h';
308309
exports.swapXYData(trace);
309310
}
@@ -332,11 +333,11 @@ exports.cleanData = function(data) {
332333
if(trace.yaxis) trace.yaxis = cleanId(trace.yaxis, 'y');
333334

334335
// scene ids scene1 -> scene
335-
if(Registry.traceIs(trace, 'gl3d') && trace.scene) {
336+
if(traceIs(trace, 'gl3d') && trace.scene) {
336337
trace.scene = Plots.subplotsRegistry.gl3d.cleanId(trace.scene);
337338
}
338339

339-
if(!Registry.traceIs(trace, 'pie') && !Registry.traceIs(trace, 'bar')) {
340+
if(!traceIs(trace, 'pie') && !traceIs(trace, 'bar') && trace.type !== 'waterfall') {
340341
if(Array.isArray(trace.textposition)) {
341342
for(i = 0; i < trace.textposition.length; i++) {
342343
trace.textposition[i] = cleanTextPosition(trace.textposition[i]);

src/plots/cartesian/axes.js

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2847,14 +2847,16 @@ function hasBarsOrFill(gd, ax) {
28472847
for(var i = 0; i < fullData.length; i++) {
28482848
var trace = fullData[i];
28492849

2850-
if(trace.visible === true &&
2851-
(trace.xaxis + trace.yaxis) === subplot &&
2852-
(
2853-
Registry.traceIs(trace, 'bar') && trace.orientation === {x: 'h', y: 'v'}[axLetter] ||
2854-
trace.fill && trace.fill.charAt(trace.fill.length - 1) === axLetter
2855-
)
2856-
) {
2857-
return true;
2850+
if(trace.visible === true && (trace.xaxis + trace.yaxis) === subplot) {
2851+
if(
2852+
(Registry.traceIs(trace, 'bar') || trace.type === 'waterfall') &&
2853+
trace.orientation === {x: 'h', y: 'v'}[axLetter]
2854+
) return true;
2855+
2856+
if(
2857+
trace.fill &&
2858+
trace.fill.charAt(trace.fill.length - 1) === axLetter
2859+
) return true;
28582860
}
28592861
}
28602862
return false;

src/plots/cartesian/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ module.exports = {
6565
traceLayerClasses: [
6666
'heatmaplayer',
6767
'contourcarpetlayer', 'contourlayer',
68-
'barlayer',
68+
'waterfalllayer', 'barlayer',
6969
'carpetlayer',
7070
'violinlayer',
7171
'boxlayer',

src/plots/cartesian/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
261261
);
262262

263263
// layers that allow `cliponaxis: false`
264-
if(className !== 'scatterlayer' && className !== 'barlayer') {
264+
if(className !== 'scatterlayer' && className !== 'barlayer' && className !== 'waterfalllayer') {
265265
Drawing.setClipUrl(sel, plotinfo.layerClipId, gd);
266266
}
267267
});
@@ -277,7 +277,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
277277
if(!gd._context.staticPlot) {
278278
if(plotinfo._hasClipOnAxisFalse) {
279279
plotinfo.clipOnAxisFalseTraces = plotinfo.plot
280-
.selectAll('.scatterlayer, .barlayer')
280+
.selectAll('.scatterlayer, .barlayer, .waterfalllayer')
281281
.selectAll('.trace');
282282
}
283283

src/traces/bar/arrays_to_calcdata.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
* LICENSE file in the root directory of this source tree.
77
*/
88

9-
109
'use strict';
1110

1211
var mergeArray = require('../../lib').mergeArray;
1312

14-
1513
// arrayOk attributes, merge them into calcdata array
1614
module.exports = function arraysToCalcdata(cd, trace) {
1715
for(var i = 0; i < cd.length; i++) cd[i].i = i;

src/traces/bar/cross_trace_calc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ function setOffsetAndWidth(gd, pa, sieve) {
237237
var fullLayout = gd._fullLayout;
238238
var bargap = fullLayout.bargap;
239239
var bargroupgap = fullLayout.bargroupgap || 0;
240+
240241
var minDiff = sieve.minDiff;
241242
var calcTraces = sieve.traces;
242243

0 commit comments

Comments
 (0)