Skip to content
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

Funnel traces #3817

Merged
merged 51 commits into from
May 7, 2019
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
3832e01
add funnel - changes to lib
archmoj Apr 13, 2019
dd5ff48
add funnel - changes to src plot plot_api and legend style
archmoj Apr 13, 2019
8846193
add funnel - chanegs to bar
archmoj Apr 13, 2019
cad13aa
add funnel - new trace files
archmoj Apr 13, 2019
87b1c44
add funnel test - mocks and baselines
archmoj Apr 13, 2019
424d6f5
add funnel jasmine test
archmoj Apr 15, 2019
aec946e
revisions after etpinard comments
archmoj Apr 26, 2019
4fb5a2b
add comment to describe how trace._base is different than trace.base …
archmoj Apr 29, 2019
75a5cb4
clean up bar cross calc - pass prefix - remove mockGd from funnel and…
archmoj Apr 30, 2019
1504463
combine blank horizontal and vertical bar text mocks in one
archmoj Apr 30, 2019
1434148
reduced number of funnel mocks
archmoj Apr 30, 2019
68bd371
remove unused handleGroupingDefaults exports from funnel and waterfal…
archmoj Apr 30, 2019
3d5b8ff
remove unused node3 link from funnel and waterfall plots
archmoj Apr 30, 2019
8d02bcf
describe non-arrayOk textinfo flags
archmoj Apr 30, 2019
c6155db
cut category types from funnel axis mocks and add anchors
archmoj Apr 30, 2019
020a34b
rm autorange true
archmoj Apr 30, 2019
4c741c7
finalize connector line and region edit types
archmoj Apr 30, 2019
eea4a72
revise funnel select and fixup select test
archmoj Apr 30, 2019
9507640
fixup axis anchors and added histogram case in image tests
archmoj Apr 30, 2019
86c0c09
pass opts to bar cross trace calc
archmoj Apr 30, 2019
bdbbeb1
remove one more unused node3 link
archmoj Apr 30, 2019
cad2728
need extra precision in textinfo values of funnel and waterfall
archmoj Apr 30, 2019
92b9471
dont coerce funnel textinfo if textposition is none - also add jasmin…
archmoj Apr 30, 2019
34e0a4b
add noCI tag for one sankey test which started to fail after adding f…
archmoj Apr 30, 2019
ba1b6c0
refactor bar waterfall and funnle plot - rm prefix - pass opts
archmoj May 1, 2019
04049f2
revisit bar-like hideOutsideRangePoints
archmoj May 1, 2019
6c8a661
default fillcolor to marker.color
archmoj May 1, 2019
2a3c354
drop funnelnorm
archmoj May 1, 2019
1c82f91
waterfall hover bug fix
archmoj May 1, 2019
6a3a13c
add jasmine test to lock waterfall hover on different types of measur…
archmoj May 1, 2019
35dfe36
coerce tick label defaults even if axis is not visible i.e. required …
archmoj May 1, 2019
c63caf9
refactor layout defaults before addressing nXn loop issue
archmoj May 2, 2019
f249c61
drop arrayOk support of bar width and offset of funnels - improve fil…
archmoj May 2, 2019
d6f023a
revise draw order for funnel connector regions and lines
archmoj May 2, 2019
0c169b5
improve image test to contain one overlay example
archmoj May 2, 2019
c29b58d
revisit textinfo and width defaults - fix and improve tests
archmoj May 3, 2019
e968da6
split handleTickLabelDefaults and split the process into two passes t…
archmoj May 2, 2019
380db2e
implement textangle for bars funnels and waterfalls - add tests
archmoj May 3, 2019
61b6068
fix alignmentgroup attributes of funnel and waterfall
archmoj May 4, 2019
0236783
refactor bar inside text if statement
archmoj May 6, 2019
4d403fd
revert cartesian layout_default file
archmoj May 6, 2019
a650170
minimal change to add logic to hide funnels
archmoj May 6, 2019
a744689
drop texangle and position defaults from funnel mocks
archmoj May 6, 2019
30b172a
fixup textangle algo - added test for outside text
archmoj May 6, 2019
446bacc
fix outside long text position with textangle - add test
archmoj May 6, 2019
b93e3a5
default funnels to horizontal
archmoj May 6, 2019
02a176a
handle multicategory labels in funnel and waterfall textinfo
archmoj May 7, 2019
d0e8fe5
add logic to reverse y axis by default if only funnels
archmoj May 7, 2019
0eb3917
remove yaxis autorange reversed from funnel mocks
archmoj May 7, 2019
fd1f6ca
improve funnel orientation description and do base waterfall and funn…
archmoj May 7, 2019
6d50386
revisit transform inside bar to reduce diff after textangle - revert …
archmoj May 7, 2019
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
11 changes: 11 additions & 0 deletions lib/funnel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Copyright 2012-2019, 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';

module.exports = require('../src/traces/funnel');
1 change: 1 addition & 0 deletions lib/index-finance.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Plotly.register([
require('./pie'),
require('./ohlc'),
require('./candlestick'),
require('./funnel'),
require('./waterfall')
]);

Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Plotly.register([
require('./contour'),
require('./scatterternary'),
require('./violin'),
require('./funnel'),
require('./waterfall'),

require('./pie'),
Expand Down
4 changes: 1 addition & 3 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,7 @@ drawing.hideOutsideRangePoints = function(traceGroups, subplot) {
var trace = d[0].trace;
var xcalendar = trace.xcalendar;
var ycalendar = trace.ycalendar;
var selector = trace.type === 'bar' ? '.bartext' :
trace.type === 'waterfall' ? '.bartext,.line' :
'.point,.textpoint';
var selector = Registry.traceIs(trace, 'bar-like') ? '.bartext' : '.point,.textpoint';

traceGroups.selectAll(selector).each(function(d) {
drawing.hideOutsideRangePoint(d, d3.select(this), xa, ya, xcalendar, ycalendar);
Expand Down
20 changes: 16 additions & 4 deletions src/components/legend/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ module.exports = function style(s, gd) {
.classed('legendpoints', true);
})
.each(styleWaterfalls)
.each(styleFunnels)
.each(styleBars)
.each(styleBoxes)
.each(stylePies)
Expand Down Expand Up @@ -306,14 +307,25 @@ module.exports = function style(s, gd) {
}

function styleBars(d) {
styleBarFamily(d, this);
}

function styleFunnels(d) {
styleBarFamily(d, this, 'funnel');
}

function styleBarFamily(d, lThis, desiredType) {
var trace = d[0].trace;
var marker = trace.marker || {};
var markerLine = marker.line || {};

var barpath = d3.select(this).select('g.legendpoints')
.selectAll('path.legendbar')
.data(Registry.traceIs(trace, 'bar') ? [d] : []);
barpath.enter().append('path').classed('legendbar', true)
var isVisible = (!desiredType) ? Registry.traceIs(trace, 'bar') :
(trace.type === desiredType && trace.visible);

var barpath = d3.select(lThis).select('g.legendpoints')
.selectAll('path.legend' + desiredType)
.data(isVisible ? [d] : []);
barpath.enter().append('path').classed('legend' + desiredType, true)
.attr('d', 'M6,6H-6V-6H6Z')
.attr('transform', 'translate(20,0)');
barpath.exit().remove();
Expand Down
2 changes: 1 addition & 1 deletion src/plot_api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ exports.cleanData = function(data) {
trace.scene = Plots.subplotsRegistry.gl3d.cleanId(trace.scene);
}

if(!traceIs(trace, 'pie') && !traceIs(trace, 'bar') && trace.type !== 'waterfall') {
if(!traceIs(trace, 'pie') && !traceIs(trace, 'bar-like')) {
if(Array.isArray(trace.textposition)) {
for(i = 0; i < trace.textposition.length; i++) {
trace.textposition[i] = cleanTextPosition(trace.textposition[i]);
Expand Down
2 changes: 1 addition & 1 deletion src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2813,7 +2813,7 @@ function hasBarsOrFill(gd, ax) {

if(trace.visible === true && (trace.xaxis + trace.yaxis) === subplot) {
if(
(Registry.traceIs(trace, 'bar') || trace.type === 'waterfall') &&
Registry.traceIs(trace, 'bar-like') &&
trace.orientation === {x: 'h', y: 'v'}[axLetter]
) return true;

Expand Down
9 changes: 5 additions & 4 deletions src/plots/cartesian/axis_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
var font = options.font || {};
var splomStash = options.splomStash || {};

var visible = coerce('visible', !options.cheateronly);
var visible = coerce('visible', !options.visibleDflt);

var axType = containerOut.type;

Expand All @@ -58,8 +58,6 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,

if(axType !== 'category' && !options.noHover) coerce('hoverformat');

if(!visible) return containerOut;

var dfltColor = coerce('color');
// if axis.color was provided, use it for fonts too; otherwise,
// inherit from global font color in case that was provided.
Expand All @@ -69,6 +67,9 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
// try to get default title from splom trace, fallback to graph-wide value
var dfltTitle = splomStash.label || layoutOut._dfltTitle[letter];

handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 1});
if(!visible) return containerOut;

coerce('title.text', dfltTitle);
Lib.coerceFont(coerce, 'title.font', {
family: font.family,
Expand All @@ -77,7 +78,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,
});

handleTickValueDefaults(containerIn, containerOut, coerce, axType);
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options);
handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, {pass: 2});
handleTickMarkDefaults(containerIn, containerOut, coerce, options);
handleLineGridDefaults(containerIn, containerOut, coerce, {
dfltColor: dfltColor,
Expand Down
9 changes: 8 additions & 1 deletion src/plots/cartesian/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,21 @@ module.exports = {
traceLayerClasses: [
'heatmaplayer',
'contourcarpetlayer', 'contourlayer',
'waterfalllayer', 'barlayer',
'funnellayer', 'waterfalllayer', 'barlayer',
'carpetlayer',
'violinlayer',
'boxlayer',
'ohlclayer',
'scattercarpetlayer', 'scatterlayer'
],

clipOnAxisFalseQuery: [
'.scatterlayer',
'.barlayer',
'.funnellayer',
'.waterfalllayer'
],

layerValue2layerClass: {
'above traces': 'above',
'below traces': 'below'
Expand Down
4 changes: 2 additions & 2 deletions src/plots/cartesian/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
);

// layers that allow `cliponaxis: false`
if(className !== 'scatterlayer' && className !== 'barlayer' && className !== 'waterfalllayer') {
if(constants.clipOnAxisFalseQuery.indexOf('.' + className) === -1) {
Drawing.setClipUrl(sel, plotinfo.layerClipId, gd);
}
});
Expand All @@ -276,7 +276,7 @@ function plotOne(gd, plotinfo, cdSubplot, transitionOpts, makeOnCompleteCallback
if(!gd._context.staticPlot) {
if(plotinfo._hasClipOnAxisFalse) {
plotinfo.clipOnAxisFalseTraces = plotinfo.plot
.selectAll('.scatterlayer, .barlayer, .waterfalllayer')
.selectAll(constants.clipOnAxisFalseQuery.join(','))
.selectAll('.trace');
}

Expand Down
152 changes: 114 additions & 38 deletions src/plots/cartesian/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,58 +28,68 @@ var Registry = require('../../registry');
var traceIs = Registry.traceIs;
var getComponentMethod = Registry.getComponentMethod;

function skipType(trace) {
return !(
traceIs(trace, 'cartesian') ||
traceIs(trace, 'gl2d')
);
}

function listNames(traceIn, xOy) {
var a = traceIn[xOy + 'axis'];
var b = traceIn[xOy + 'axes'];

var list = [];
if(a) {
list = [a];
} else if(b) {
list = b;
}

return list;
}

function appendList(cont, k, item) {
if(Array.isArray(cont[k])) cont[k].push(item);
else cont[k] = [item];
}

function getName(trace, xOy) {
return (trace[xOy + 'axis']) ? id2name(trace[xOy + 'axis']) : undefined; // TODO: why these should be left undefined?
}

module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
var ax2traces = {};
var xaCheater = {};
var xaNonCheater = {};
var hideX = {};
var hideY = {};
var outerTicks = {};
var noGrids = {};
var i, j;
var trace;
var xaName, yaName;

// look for axes in the data
for(i = 0; i < fullData.length; i++) {
var trace = fullData[i];
if(!traceIs(trace, 'cartesian') && !traceIs(trace, 'gl2d')) continue;

var xaName;
if(trace.xaxis) {
xaName = id2name(trace.xaxis);
appendList(ax2traces, xaName, trace);
} else if(trace.xaxes) {
for(j = 0; j < trace.xaxes.length; j++) {
appendList(ax2traces, id2name(trace.xaxes[j]), trace);
}
function append(list) {
for(var k = 0; k < list.length; k++) {
appendList(ax2traces, id2name(list[k]), trace);
}
}

var yaName;
if(trace.yaxis) {
yaName = id2name(trace.yaxis);
appendList(ax2traces, yaName, trace);
} else if(trace.yaxes) {
for(j = 0; j < trace.yaxes.length; j++) {
appendList(ax2traces, id2name(trace.yaxes[j]), trace);
}
}
// create lists
for(i = 0; i < fullData.length; i++) {
trace = fullData[i];
if(skipType(trace)) continue;

// Two things trigger axis visibility:
// 1. is not carpet
// 2. carpet that's not cheater
if(!traceIs(trace, 'carpet') || (trace.type === 'carpet' && !trace._cheater)) {
if(xaName) xaNonCheater[xaName] = 1;
}
append(listNames(trace, 'x'));
append(listNames(trace, 'y'));
}

// The above check for definitely-not-cheater is not adequate. This
// second list tracks which axes *could* be a cheater so that the
// full condition triggering hiding is:
// *could* be a cheater and *is not definitely visible*
if(trace.type === 'carpet' && trace._cheater) {
if(xaName) xaCheater[xaName] = 1;
}
// look for axes in the data
for(i = 0; i < fullData.length; i++) {
trace = fullData[i];
if(skipType(trace)) continue;

xaName = getName(trace, 'x');
yaName = getName(trace, 'y');

// check for default formatting tweaks
if(traceIs(trace, '2dMap')) {
Expand All @@ -93,6 +103,72 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
}
}

function includesOnly(desiredType, xaNameIn, yaNameIn) {
var result = false;
for(var k = 0; k < fullData.length; k++) {
etpinard marked this conversation as resolved.
Show resolved Hide resolved
var otherTrace = fullData[k];
if(skipType(otherTrace)) continue;

if(
xaNameIn !== getName(otherTrace, 'x') ||
yaNameIn !== getName(otherTrace, 'y')
) continue;

var found = false;

if(desiredType === 'cheater' && traceIs(trace, 'carpet') && trace._cheater !== false) {
found = true;
} else if(trace.type === desiredType) {
found = true;
}

if(!found) {
result = false;
break;
}
result = true;
}
return result;
}

var funnelOnlyX = {};
var funnelOnlyY = {};
var cheaterOnlyX = {};

for(i = 0; i < fullData.length; i++) {
trace = fullData[i];
if(skipType(trace)) continue;

xaName = getName(trace, 'x');
yaName = getName(trace, 'y');

if(funnelOnlyX[xaName] !== false) funnelOnlyX[xaName] = includesOnly('funnel', xaName, yaName);
if(funnelOnlyY[yaName] !== false) funnelOnlyY[yaName] = includesOnly('funnel', xaName, yaName);
if(cheaterOnlyX[xaName] !== false) cheaterOnlyX[xaName] = includesOnly('cheater', xaName, yaName);
}

for(i = 0; i < fullData.length; i++) {
trace = fullData[i];
if(skipType(trace)) continue;

xaName = getName(trace, 'x');
yaName = getName(trace, 'y');

if(traceIs(trace, 'carpet') && trace._cheater) {
if(cheaterOnlyX[xaName] && xaName) hideX[xaName] = 1;
}

if(trace.type === 'funnel') {
if(funnelOnlyX[xaName] && trace.orientation === 'h') {
hideX[xaName] = 1;
}

if(funnelOnlyY[yaName] && trace.orientation === 'v') {
hideY[yaName] = 1;
}
}
}

var subplots = layoutOut._subplots;
var xIds = subplots.xaxis;
var yIds = subplots.yaxis;
Expand Down Expand Up @@ -176,7 +252,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
bgColor: bgColor,
calendar: layoutOut.calendar,
automargin: true,
cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName],
visibleDflt: (axLetter === 'x' && !!hideX[axName]) || (axLetter === 'y' && !!hideY[axName]),
splomStash: ((layoutOut._splomAxes || {})[axLetter] || {})[id]
};

Expand Down
24 changes: 22 additions & 2 deletions src/plots/cartesian/tick_label_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,27 @@ var Lib = require('../../lib');
var layoutAttributes = require('./layout_attributes');
var handleArrayContainerDefaults = require('../array_container_defaults');

module.exports = function handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options) {
module.exports = function handleTickLabelDefaults(containerIn, containerOut, coerce, axType, options, config) {
if(!config || config.pass === 1) {
handlePrefixSuffix(containerIn, containerOut, coerce, axType, options);
}

if(!config || config.pass === 2) {
handleOtherDefaults(containerIn, containerOut, coerce, axType, options);
}
};

function handlePrefixSuffix(containerIn, containerOut, coerce, axType, options) {
var showAttrDflt = getShowAttrDflt(containerIn);

var tickPrefix = coerce('tickprefix');
if(tickPrefix) coerce('showtickprefix', showAttrDflt);

var tickSuffix = coerce('ticksuffix', options.tickSuffixDflt);
if(tickSuffix) coerce('showticksuffix', showAttrDflt);
}

function handleOtherDefaults(containerIn, containerOut, coerce, axType, options) {
var showAttrDflt = getShowAttrDflt(containerIn);

var tickPrefix = coerce('tickprefix');
Expand Down Expand Up @@ -54,7 +74,7 @@ module.exports = function handleTickLabelDefaults(containerIn, containerOut, coe
}
}
}
};
}

/*
* Attributes 'showexponent', 'showtickprefix' and 'showticksuffix'
Expand Down
Loading