From d3b5068b67529681ead63d5c0d9a1d4ce59b5e77 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Sat, 1 Jun 2024 14:48:29 +0200 Subject: [PATCH 01/23] For bar traces make offsetgroup work with barmode 'stacked' and 'relative' --- src/traces/bar/cross_trace_calc.js | 56 ++++--------------- src/traces/bar/defaults.js | 4 +- src/traces/bar/layout_defaults.js | 12 +++- src/traces/scatter/grouping_defaults.js | 7 ++- .../mocks/zzz_bar_relative_offsetgroup.json | 48 ++++++++++++++++ 5 files changed, 73 insertions(+), 54 deletions(-) create mode 100644 test/image/mocks/zzz_bar_relative_offsetgroup.json diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 61df5cf4d23..840805c3928 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -75,7 +75,7 @@ function setGroupPositions(gd, pa, sa, calcTraces, opts) { switch(opts.mode) { case 'overlay': - setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts); + setGroupPositionsInOverlayMode(gd, pa, sa, calcTraces, opts); break; case 'group': @@ -94,7 +94,7 @@ function setGroupPositions(gd, pa, sa, calcTraces, opts) { setGroupPositionsInGroupMode(gd, pa, sa, included, opts); } if(excluded.length) { - setGroupPositionsInOverlayMode(pa, sa, excluded, opts); + setGroupPositionsInOverlayMode(gd, pa, sa, excluded, opts); } break; @@ -119,7 +119,7 @@ function setGroupPositions(gd, pa, sa, calcTraces, opts) { setGroupPositionsInStackOrRelativeMode(gd, pa, sa, included, opts); } if(excluded.length) { - setGroupPositionsInOverlayMode(pa, sa, excluded, opts); + setGroupPositionsInOverlayMode(gd, pa, sa, excluded, opts); } break; } @@ -217,7 +217,7 @@ function initBase(sa, calcTraces) { } } -function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) { +function setGroupPositionsInOverlayMode(gd, pa, sa, calcTraces, opts) { // update position axis and set bar offsets and widths for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; @@ -229,7 +229,7 @@ function setGroupPositionsInOverlayMode(pa, sa, calcTraces, opts) { }); // set bar offsets and widths, and update position axis - setOffsetAndWidth(pa, sieve, opts); + setOffsetAndWidth(gd, pa, sieve, opts); // set bar bases and sizes, and update size axis // @@ -253,7 +253,7 @@ function setGroupPositionsInGroupMode(gd, pa, sa, calcTraces, opts) { }); // set bar offsets and widths, and update position axis - setOffsetAndWidthInGroupMode(gd, pa, sieve, opts); + setOffsetAndWidth(gd, pa, sieve, opts); // relative-stack bars within the same trace that would otherwise // be hidden @@ -276,7 +276,7 @@ function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) { }); // set bar offsets and widths, and update position axis - setOffsetAndWidth(pa, sieve, opts); + setOffsetAndWidth(gd, pa, sieve, opts); // set bar bases and sizes, and update size axis stackBars(sa, sieve, opts); @@ -300,43 +300,7 @@ function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) { if(opts.norm) normalizeBars(sa, sieve, opts); } -function setOffsetAndWidth(pa, sieve, opts) { - var minDiff = sieve.minDiff; - var calcTraces = sieve.traces; - - // set bar offsets and widths - var barGroupWidth = minDiff * (1 - opts.gap); - var barWidthPlusGap = barGroupWidth; - var barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); - - // computer bar group center and bar offset - var offsetFromCenter = -barWidth / 2; - - for(var i = 0; i < calcTraces.length; i++) { - var calcTrace = calcTraces[i]; - var t = calcTrace[0].t; - - // store bar width and offset for this trace - t.barwidth = barWidth; - t.poffset = offsetFromCenter; - t.bargroupwidth = barGroupWidth; - t.bardelta = minDiff; - } - - // stack bars that only differ by rounding - sieve.binWidth = calcTraces[0][0].t.barwidth / 100; - - // if defined, apply trace offset and width - applyAttributes(sieve); - - // store the bar center in each calcdata item - setBarCenterAndWidth(pa, sieve); - - // update position axes - updatePositionAxis(pa, sieve); -} - -function setOffsetAndWidthInGroupMode(gd, pa, sieve, opts) { +function setOffsetAndWidth(gd, pa, sieve, opts) { var fullLayout = gd._fullLayout; var positions = sieve.positions; var distinctPositions = sieve.distinctPositions; @@ -615,6 +579,7 @@ function stackBars(sa, sieve, opts) { isFunnel = (fullTrace.type === 'funnel'); + var offset = calcTrace[0].t.poffset; var pts = []; for(j = 0; j < calcTrace.length; j++) { @@ -629,8 +594,7 @@ function stackBars(sa, sieve, opts) { value = bar.s + bar.b; } - var base = sieve.put(bar.p, value); - + var base = sieve.put(bar.p + offset, value); var top = base + value; // store the bar base and top in each calcdata item diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js index b969e30b1ee..2409ca5a113 100644 --- a/src/traces/bar/defaults.js +++ b/src/traces/bar/defaults.js @@ -80,9 +80,7 @@ function crossTraceDefaults(fullData, fullLayout) { traceOut.marker.cornerradius = validateCornerradius(r); } - if(fullLayout.barmode === 'group') { - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); - } + handleGroupingDefaults(fullLayout.barmode, traceIn, traceOut, fullLayout, coerce); } } } diff --git a/src/traces/bar/layout_defaults.js b/src/traces/bar/layout_defaults.js index bebe022d8a6..89546a26296 100644 --- a/src/traces/bar/layout_defaults.js +++ b/src/traces/bar/layout_defaults.js @@ -19,6 +19,7 @@ module.exports = function(layoutIn, layoutOut, fullData) { var usedSubplots = {}; var mode = coerce('barmode'); + var isGroup = mode === 'group'; for(var i = 0; i < fullData.length; i++) { var trace = fullData[i]; @@ -27,10 +28,17 @@ module.exports = function(layoutIn, layoutOut, fullData) { // if we have at least 2 grouped bar traces on the same subplot, // we should default to a gap anyway, even if the data is histograms - if(mode === 'group') { - var subploti = trace.xaxis + trace.yaxis; + var subploti = trace.xaxis + trace.yaxis; + if(isGroup) { + // with barmode group, bars are grouped next to each other when sharing the same axes if(usedSubplots[subploti]) gappedAnyway = true; usedSubplots[subploti] = true; + } else { + // with other barmodes bars are grouped next to each other when sharing the same axes + // and using different offsetgroups + subploti += trace._input.offsetgroup; + if(!usedSubplots[subploti]) gappedAnyway = true; + usedSubplots[subploti] = true; } if(trace.visible && trace.type === 'histogram') { diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index de957569108..509917a0697 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -2,7 +2,7 @@ var getAxisGroup = require('../../plots/cartesian/constraints').getAxisGroup; -module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce) { +module.exports = function handleGroupingDefaults(barmode, traceIn, traceOut, fullLayout, coerce) { var orientation = traceOut.orientation; // N.B. grouping is done across all trace types that support it var posAxId = traceOut[{v: 'x', h: 'y'}[orientation] + 'axis']; @@ -29,8 +29,9 @@ module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, var offsetgroup = coerce('offsetgroup'); var offsetGroups = alignmentGroupOpts.offsetGroups; var offsetGroupOpts = offsetGroups[offsetgroup]; - - if(offsetgroup) { + // in barmode 'group', traces without offsetgroup receive their own offsetgroup + // in other barmodes, traces without offsetgroup are assigned to the same offset group + if(barmode !== 'group' || offsetgroup) { if(!offsetGroupOpts) { offsetGroupOpts = offsetGroups[offsetgroup] = { offsetIndex: Object.keys(offsetGroups).length diff --git a/test/image/mocks/zzz_bar_relative_offsetgroup.json b/test/image/mocks/zzz_bar_relative_offsetgroup.json new file mode 100644 index 00000000000..be01ea80fe1 --- /dev/null +++ b/test/image/mocks/zzz_bar_relative_offsetgroup.json @@ -0,0 +1,48 @@ +{ + "data": [ + { + "type": "bar", + "x": [ "A", "B", "C"], + "y": [ 10, 10, 10 ], + "offsetgroup": 1, + "hovertext": "offsetgroup: 1" + }, + { + "type": "bar", + "x": [ "A", "B", "C"], + "y": [ 20, 20, 20 ], + "offsetgroup": 1, + "hovertext": "offsetgroup: 1" + }, + { + "type": "bar", + "x": [ "A", "B", "C"], + "y": [ 30, 30, 30 ], + "offsetgroup": 2, + "hovertext": "offsetgroup: 2" + }, + { + "type": "bar", + "x": [ "A", "B", "C"], + "y": [ 40, 40, 40 ], + "offsetgroup": 2, + "hovertext": "offsetgroup: 2" + }, + { + "type": "bar", + "x": [ "A", "B", "C"], + "y": [ -50, 50, 50 ], + "offsetgroup": 2, + "hovertext": "offsetgroup: 2" + } + ], + "layout": { + "width": 600, + "showlegend": false, + "barmode": "relative", + "title": { + "text": "Separately stacked bars with barmode 'relative'" + } + } + } + \ No newline at end of file From 6ce9aa62bfaf01659303ec55412166c4ddc9ef8e Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 3 Jun 2024 18:08:41 +0200 Subject: [PATCH 02/23] Fix handleGroupingDefaults calls outside of bar/defaults.js --- src/traces/bar/defaults.js | 2 +- src/traces/scatter/grouping_defaults.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/traces/bar/defaults.js b/src/traces/bar/defaults.js index 2409ca5a113..66cd408b06f 100644 --- a/src/traces/bar/defaults.js +++ b/src/traces/bar/defaults.js @@ -80,7 +80,7 @@ function crossTraceDefaults(fullData, fullLayout) { traceOut.marker.cornerradius = validateCornerradius(r); } - handleGroupingDefaults(fullLayout.barmode, traceIn, traceOut, fullLayout, coerce); + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.barmode); } } } diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index 509917a0697..12344a1c7d6 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -2,7 +2,7 @@ var getAxisGroup = require('../../plots/cartesian/constraints').getAxisGroup; -module.exports = function handleGroupingDefaults(barmode, traceIn, traceOut, fullLayout, coerce) { +module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, barmode) { var orientation = traceOut.orientation; // N.B. grouping is done across all trace types that support it var posAxId = traceOut[{v: 'x', h: 'y'}[orientation] + 'axis']; @@ -31,7 +31,8 @@ module.exports = function handleGroupingDefaults(barmode, traceIn, traceOut, ful var offsetGroupOpts = offsetGroups[offsetgroup]; // in barmode 'group', traces without offsetgroup receive their own offsetgroup // in other barmodes, traces without offsetgroup are assigned to the same offset group - if(barmode !== 'group' || offsetgroup) { + var isBarTrace = traceOut.type === 'bar' || traceOut.type === 'waterfall'; + if((isBarTrace && barmode !== 'group') || offsetgroup) { if(!offsetGroupOpts) { offsetGroupOpts = offsetGroups[offsetgroup] = { offsetIndex: Object.keys(offsetGroups).length From 7664219643d8249074dd435faa993b08ac82f8f4 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 3 Jun 2024 18:09:14 +0200 Subject: [PATCH 03/23] Fix linter error on missing newline at EOF --- test/image/mocks/zzz_bar_relative_offsetgroup.json | 1 - 1 file changed, 1 deletion(-) diff --git a/test/image/mocks/zzz_bar_relative_offsetgroup.json b/test/image/mocks/zzz_bar_relative_offsetgroup.json index be01ea80fe1..9c9df9097f4 100644 --- a/test/image/mocks/zzz_bar_relative_offsetgroup.json +++ b/test/image/mocks/zzz_bar_relative_offsetgroup.json @@ -45,4 +45,3 @@ } } } - \ No newline at end of file From ed7d5417f66b22e72110d5cef4cf163eefcdf4cd Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Tue, 4 Jun 2024 18:33:00 +0200 Subject: [PATCH 04/23] Fix offset calculation and stacking for barpolar barpolar trace has no offsetgroup property --- src/traces/bar/cross_trace_calc.js | 58 ++++++++++++++++++------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 840805c3928..6aa3f744e50 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -311,34 +311,43 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { // if there aren't any overlapping positions, // let them have full width even if mode is group var overlap = (positions.length !== distinctPositions.length); - var barGroupWidth = minDiff * (1 - opts.gap); - var groupId = getAxisGroup(fullLayout, pa._id) + calcTraces[0][0].trace.orientation; - var alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; + var barGroupWidth = minDiff * (1 - opts.gap); + var barWidthPlusGap; + var barWidth; + var offsetFromCenter; + var alignmentGroups; + if(pa._id === 'angularaxis') { + barWidthPlusGap = barGroupWidth; + barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); + offsetFromCenter = -barWidth / 2; + } else { // collect groups and calculate values in loop below + var groupId = getAxisGroup(fullLayout, pa._id) + calcTraces[0][0].trace.orientation; + alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; + } for(var i = 0; i < nTraces; i++) { var calcTrace = calcTraces[i]; var trace = calcTrace[0].trace; + if(pa._id !== 'angularaxis') { + var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; + var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; - var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; - var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; - - var barWidthPlusGap; - if(nOffsetGroups) { - barWidthPlusGap = barGroupWidth / nOffsetGroups; - } else { - barWidthPlusGap = overlap ? barGroupWidth / nTraces : barGroupWidth; - } + if(nOffsetGroups) { + barWidthPlusGap = barGroupWidth / nOffsetGroups; + } else { + barWidthPlusGap = overlap ? barGroupWidth / nTraces : barGroupWidth; + } - var barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); + barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); - var offsetFromCenter; - if(nOffsetGroups) { - offsetFromCenter = ((2 * trace._offsetIndex + 1 - nOffsetGroups) * barWidthPlusGap - barWidth) / 2; - } else { - offsetFromCenter = overlap ? - ((2 * i + 1 - nTraces) * barWidthPlusGap - barWidth) / 2 : - -barWidth / 2; + if(nOffsetGroups) { + offsetFromCenter = ((2 * trace._offsetIndex + 1 - nOffsetGroups) * barWidthPlusGap - barWidth) / 2; + } else { + offsetFromCenter = overlap ? + ((2 * i + 1 - nTraces) * barWidthPlusGap - barWidth) / 2 : + -barWidth / 2; + } } var t = calcTrace[0].t; @@ -358,7 +367,11 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { setBarCenterAndWidth(pa, sieve); // update position axes - updatePositionAxis(pa, sieve, overlap); + if(pa._id !== 'angularaxis') { + updatePositionAxis(pa, sieve); + } else { + updatePositionAxis(pa, sieve, overlap); + } } function applyAttributes(sieve) { @@ -579,7 +592,8 @@ function stackBars(sa, sieve, opts) { isFunnel = (fullTrace.type === 'funnel'); - var offset = calcTrace[0].t.poffset; + var offset = fullTrace.type === 'barpolar' ? 0 : calcTrace[0].t.poffset; + var pts = []; for(j = 0; j < calcTrace.length; j++) { From 24b4fb5afe14c4b86c473166876e676ddba68f3d Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 5 Jun 2024 16:49:47 +0200 Subject: [PATCH 05/23] Fix angularaxis check in setOffsetAndWidth --- src/traces/bar/cross_trace_calc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 6aa3f744e50..88fbffd87d1 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -367,7 +367,7 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { setBarCenterAndWidth(pa, sieve); // update position axes - if(pa._id !== 'angularaxis') { + if(pa._id === 'angularaxis') { updatePositionAxis(pa, sieve); } else { updatePositionAxis(pa, sieve, overlap); From c91f06cd26c55c51ab808848d1b9a0e3db9d5583 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 5 Jun 2024 16:49:10 +0200 Subject: [PATCH 06/23] consider modes of other traces as well (scattermode, funnelmode,... ) --- src/traces/box/defaults.js | 4 +--- src/traces/funnel/defaults.js | 11 ++++------- src/traces/scatter/cross_trace_defaults.js | 12 +++++------- src/traces/scatter/grouping_defaults.js | 3 +-- src/traces/waterfall/defaults.js | 10 ++++------ 5 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index 0e9a5a71591..e9fdeb87c18 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -303,9 +303,7 @@ function crossTraceDefaults(fullData, fullLayout) { if(traceType === 'box' || traceType === 'violin') { traceIn = traceOut._input; - if(fullLayout[traceType + 'mode'] === 'group') { - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); - } + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout[traceType + 'mode']); } } } diff --git a/src/traces/funnel/defaults.js b/src/traces/funnel/defaults.js index b8bd941f68e..5e40a48bb91 100644 --- a/src/traces/funnel/defaults.js +++ b/src/traces/funnel/defaults.js @@ -77,13 +77,10 @@ function crossTraceDefaults(fullData, fullLayout) { return Lib.coerce(traceOut._input, traceOut, attributes, attr); } - if(fullLayout.funnelmode === 'group') { - for(var i = 0; i < fullData.length; i++) { - traceOut = fullData[i]; - traceIn = traceOut._input; - - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); - } + for(var i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; + traceIn = traceOut._input; + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.funnelmode); } } diff --git a/src/traces/scatter/cross_trace_defaults.js b/src/traces/scatter/cross_trace_defaults.js index 6505c6573d7..67eb2790e29 100644 --- a/src/traces/scatter/cross_trace_defaults.js +++ b/src/traces/scatter/cross_trace_defaults.js @@ -12,14 +12,12 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { return Lib.coerce(traceOut._input, traceOut, attributes, attr); } - if(fullLayout.scattermode === 'group') { - for(i = 0; i < fullData.length; i++) { - traceOut = fullData[i]; + for(i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; - if(traceOut.type === 'scatter') { - traceIn = traceOut._input; - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); - } + if(traceOut.type === 'scatter') { + traceIn = traceOut._input; + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.scattermode); } } diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index 12344a1c7d6..88aee60fb85 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -31,8 +31,7 @@ module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, var offsetGroupOpts = offsetGroups[offsetgroup]; // in barmode 'group', traces without offsetgroup receive their own offsetgroup // in other barmodes, traces without offsetgroup are assigned to the same offset group - var isBarTrace = traceOut.type === 'bar' || traceOut.type === 'waterfall'; - if((isBarTrace && barmode !== 'group') || offsetgroup) { + if(barmode !== 'group' || offsetgroup) { if(!offsetGroupOpts) { offsetGroupOpts = offsetGroups[offsetgroup] = { offsetIndex: Object.keys(offsetGroups).length diff --git a/src/traces/waterfall/defaults.js b/src/traces/waterfall/defaults.js index 067d8aded90..c6d62b69fc5 100644 --- a/src/traces/waterfall/defaults.js +++ b/src/traces/waterfall/defaults.js @@ -86,13 +86,11 @@ function crossTraceDefaults(fullData, fullLayout) { return Lib.coerce(traceOut._input, traceOut, attributes, attr); } - if(fullLayout.waterfallmode === 'group') { - for(var i = 0; i < fullData.length; i++) { - traceOut = fullData[i]; - traceIn = traceOut._input; + for(var i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; + traceIn = traceOut._input; - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce); - } + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.waterfallmode); } } From 724c83fb43d2b218a1a3cbe93ea0a12bf15715f4 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 5 Jun 2024 16:52:48 +0200 Subject: [PATCH 07/23] Don't use poffset for sieve.put, use trace._offsetIndex instead. poffset is not only different for different offsetgroups but also when the trace has a different width. --- src/traces/bar/cross_trace_calc.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 88fbffd87d1..1b2098f5d63 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -352,6 +352,7 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { var t = calcTrace[0].t; t.barwidth = barWidth; + t.offsetindex = trace._offsetIndex; t.poffset = offsetFromCenter; t.bargroupwidth = barGroupWidth; t.bardelta = minDiff; @@ -569,18 +570,20 @@ function stackBars(sa, sieve, opts) { var isFunnel; var i, j; var bar; + var offsetIndex; for(i = 0; i < calcTraces.length; i++) { calcTrace = calcTraces[i]; fullTrace = calcTrace[0].trace; if(fullTrace.type === 'funnel') { + offsetIndex = calcTrace[0].t.offsetindex; for(j = 0; j < calcTrace.length; j++) { bar = calcTrace[j]; if(bar.s !== BADNUM) { // create base of funnels - sieve.put(bar.p, -0.5 * bar.s); + sieve.put(bar.p + offsetIndex, -0.5 * bar.s); } } } @@ -592,7 +595,7 @@ function stackBars(sa, sieve, opts) { isFunnel = (fullTrace.type === 'funnel'); - var offset = fullTrace.type === 'barpolar' ? 0 : calcTrace[0].t.poffset; + offsetIndex = fullTrace.type === 'barpolar' ? 0 : calcTrace[0].t.offsetindex; var pts = []; @@ -608,7 +611,7 @@ function stackBars(sa, sieve, opts) { value = bar.s + bar.b; } - var base = sieve.put(bar.p + offset, value); + var base = sieve.put(bar.p + offsetIndex, value); var top = base + value; // store the bar base and top in each calcdata item From 315c8886e811926647974cdf39c0a5fe64ba633f Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 5 Jun 2024 17:09:11 +0200 Subject: [PATCH 08/23] Fix logic for adding a gap between bars --- src/traces/bar/layout_defaults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/bar/layout_defaults.js b/src/traces/bar/layout_defaults.js index 89546a26296..47f417d6326 100644 --- a/src/traces/bar/layout_defaults.js +++ b/src/traces/bar/layout_defaults.js @@ -37,7 +37,7 @@ module.exports = function(layoutIn, layoutOut, fullData) { // with other barmodes bars are grouped next to each other when sharing the same axes // and using different offsetgroups subploti += trace._input.offsetgroup; - if(!usedSubplots[subploti]) gappedAnyway = true; + if(usedSubplots.length > 0 && !usedSubplots[subploti]) gappedAnyway = true; usedSubplots[subploti] = true; } From c6f5dbe85479320c40f5ef8058d95a21f7ac8890 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 5 Jun 2024 17:25:33 +0200 Subject: [PATCH 09/23] baseline image for zzz_bar_relative_offsetgroup --- .../baselines/zzz_bar_relative_offsetgroup.png | Bin 0 -> 17958 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test/image/baselines/zzz_bar_relative_offsetgroup.png diff --git a/test/image/baselines/zzz_bar_relative_offsetgroup.png b/test/image/baselines/zzz_bar_relative_offsetgroup.png new file mode 100644 index 0000000000000000000000000000000000000000..a95edace642af4c83211843346915950ee91b8a4 GIT binary patch literal 17958 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 Date: Thu, 6 Jun 2024 16:09:30 +0200 Subject: [PATCH 10/23] Fix sieve for offsetgroups Previous attempt that used bar.p + offsetIndex resulted in the same bin for a bar with bar.p 0 and offsetIndex 1 and a bar with bar.p 1 and offsetIndex 0 --- src/traces/bar/cross_trace_calc.js | 18 ++++++++++-------- src/traces/bar/sieve.js | 12 ++++++------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 1b2098f5d63..7a898db23f8 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -284,12 +284,12 @@ function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) { // flag the outmost bar (for text display purposes) for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; - + var offsetIndex = calcTrace[0].t.offsetindex; for(var j = 0; j < calcTrace.length; j++) { var bar = calcTrace[j]; if(bar.s !== BADNUM) { - var isOutmostBar = ((bar.b + bar.s) === sieve.get(bar.p, bar.s)); + var isOutmostBar = ((bar.b + bar.s) === sieve.get(bar.p, offsetIndex, bar.s)); if(isOutmostBar) bar._outmost = true; } } @@ -583,7 +583,7 @@ function stackBars(sa, sieve, opts) { if(bar.s !== BADNUM) { // create base of funnels - sieve.put(bar.p + offsetIndex, -0.5 * bar.s); + sieve.put(bar.p, offsetIndex, -0.5 * bar.s); } } } @@ -611,7 +611,7 @@ function stackBars(sa, sieve, opts) { value = bar.s + bar.b; } - var base = sieve.put(bar.p + offsetIndex, value); + var base = sieve.put(bar.p, offsetIndex, value); var top = base + value; // store the bar base and top in each calcdata item @@ -644,12 +644,12 @@ function sieveBars(sieve) { for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; - + var offsetIndex = calcTrace[0].t.offsetindex; for(var j = 0; j < calcTrace.length; j++) { var bar = calcTrace[j]; if(bar.s !== BADNUM) { - sieve.put(bar.p, bar.b + bar.s); + sieve.put(bar.p, offsetIndex, bar.b + bar.s); } } } @@ -661,6 +661,7 @@ function unhideBarsWithinTrace(sieve, pa) { for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; var fullTrace = calcTrace[0].trace; + var offsetIndex = calcTrace[0].t.offsetindex; if(fullTrace.base === undefined) { var inTraceSieve = new Sieve([calcTrace], { @@ -674,7 +675,7 @@ function unhideBarsWithinTrace(sieve, pa) { if(bar.p !== BADNUM) { // stack current bar and get previous sum - var base = inTraceSieve.put(bar.p, bar.b + bar.s); + var base = inTraceSieve.put(bar.p, offsetIndex, bar.b + bar.s); // if previous sum if non-zero, this means: // multiple bars have same starting point are potentially hidden, @@ -707,6 +708,7 @@ function normalizeBars(sa, sieve, opts) { for(var i = 0; i < calcTraces.length; i++) { var calcTrace = calcTraces[i]; + var offsetIndex = calcTrace[0].t.offsetindex; var fullTrace = calcTrace[0].trace; var pts = []; var tozero = false; @@ -716,7 +718,7 @@ function normalizeBars(sa, sieve, opts) { var bar = calcTrace[j]; if(bar.s !== BADNUM) { - var scale = Math.abs(sTop / sieve.get(bar.p, bar.s)); + var scale = Math.abs(sTop / sieve.get(bar.p, offsetIndex, bar.s)); bar.b *= scale; bar.s *= scale; diff --git a/src/traces/bar/sieve.js b/src/traces/bar/sieve.js index 54dc5a74b25..1368d34d345 100644 --- a/src/traces/bar/sieve.js +++ b/src/traces/bar/sieve.js @@ -69,8 +69,8 @@ function Sieve(traces, opts) { * @param {number} value * @returns {number} Previous bin value */ -Sieve.prototype.put = function put(position, value) { - var label = this.getLabel(position, value); +Sieve.prototype.put = function put(position, group, value) { + var label = this.getLabel(position, group, value); var oldValue = this.bins[label] || 0; this.bins[label] = oldValue + value; @@ -87,8 +87,8 @@ Sieve.prototype.put = function put(position, value) { * (required if this.sepNegVal is true) * @returns {number} Current bin value */ -Sieve.prototype.get = function get(position, value) { - var label = this.getLabel(position, value); +Sieve.prototype.get = function get(position, group, value) { + var label = this.getLabel(position, group, value); return this.bins[label] || 0; }; @@ -103,10 +103,10 @@ Sieve.prototype.get = function get(position, value) { * (prefixed with a 'v' if value is negative and this.sepNegVal is * true; otherwise prefixed with '^') */ -Sieve.prototype.getLabel = function getLabel(position, value) { +Sieve.prototype.getLabel = function getLabel(position, group, value) { var prefix = (value < 0 && this.sepNegVal) ? 'v' : '^'; var label = (this.overlapNoMerge) ? position : Math.round(position / this.binWidth); - return prefix + label; + return prefix + label + 'g' + group; }; From 2d9d0a925e08b7348b88e52eecaf3be09476861a Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Thu, 6 Jun 2024 18:06:11 +0200 Subject: [PATCH 11/23] Fix for failing baseline test waterfall_funnel_template_date --- src/traces/funnel/defaults.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/traces/funnel/defaults.js b/src/traces/funnel/defaults.js index 5e40a48bb91..02a7ad47efa 100644 --- a/src/traces/funnel/defaults.js +++ b/src/traces/funnel/defaults.js @@ -79,8 +79,10 @@ function crossTraceDefaults(fullData, fullLayout) { for(var i = 0; i < fullData.length; i++) { traceOut = fullData[i]; - traceIn = traceOut._input; - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.funnelmode); + if(traceOut.type === 'funnel') { + traceIn = traceOut._input; + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.funnelmode); + } } } From 8caa69b4aeb593fc1bd171aa72db66ae573d0c05 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Thu, 6 Jun 2024 18:10:54 +0200 Subject: [PATCH 12/23] Pass missing barmode param for histogram --- src/traces/histogram/cross_trace_defaults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/histogram/cross_trace_defaults.js b/src/traces/histogram/cross_trace_defaults.js index d389c095b68..7342360af0f 100644 --- a/src/traces/histogram/cross_trace_defaults.js +++ b/src/traces/histogram/cross_trace_defaults.js @@ -112,7 +112,7 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { // N.B. need to coerce *alignmentgroup* before *bingroup*, as traces // in same alignmentgroup "have to match" if(!traceIs(traceOut, '2dMap')) { - handleGroupingDefaults(traceOut._input, traceOut, fullLayout, coerce); + handleGroupingDefaults(traceOut._input, traceOut, fullLayout, coerce, fullLayout.barmode); } } } From 68fae33d696ae7db8f2837aaa8b2b06e6a76ddad Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Thu, 6 Jun 2024 18:12:31 +0200 Subject: [PATCH 13/23] Ensure offsetIndex and offsetgroup are not undefined --- src/traces/bar/cross_trace_calc.js | 2 +- src/traces/scatter/grouping_defaults.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 7a898db23f8..e89b406f5fd 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -352,7 +352,7 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { var t = calcTrace[0].t; t.barwidth = barWidth; - t.offsetindex = trace._offsetIndex; + t.offsetindex = trace._offsetIndex || 0; t.poffset = offsetFromCenter; t.bargroupwidth = barGroupWidth; t.bardelta = minDiff; diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index 88aee60fb85..3c3f488ec86 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -26,11 +26,12 @@ module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, }; } - var offsetgroup = coerce('offsetgroup'); + var offsetgroup = coerce('offsetgroup') || ''; var offsetGroups = alignmentGroupOpts.offsetGroups; var offsetGroupOpts = offsetGroups[offsetgroup]; // in barmode 'group', traces without offsetgroup receive their own offsetgroup // in other barmodes, traces without offsetgroup are assigned to the same offset group + traceOut._offsetIndex = 0; if(barmode !== 'group' || offsetgroup) { if(!offsetGroupOpts) { offsetGroupOpts = offsetGroups[offsetgroup] = { From e8bd5db9fb6cc42ecccf0108865816750c976d2d Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Fri, 7 Jun 2024 14:40:48 +0200 Subject: [PATCH 14/23] Track alignmentgroups in fullLayout._alignmentOpts by trace type Previously, all offsetgroups of different trace types were listed together, leading to undesired grouping interaction between different trace types. Fixes failing baseline test "legendgroup". --- src/traces/bar/cross_trace_calc.js | 5 +++-- src/traces/box/cross_trace_calc.js | 11 +++++++---- src/traces/histogram/cross_trace_defaults.js | 8 +++++--- src/traces/scatter/grouping_defaults.js | 7 ++++++- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index e89b406f5fd..74be462c37c 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -322,8 +322,9 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); offsetFromCenter = -barWidth / 2; } else { // collect groups and calculate values in loop below - var groupId = getAxisGroup(fullLayout, pa._id) + calcTraces[0][0].trace.orientation; - alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; + var firstTrace = calcTraces[0][0].trace; + var groupId = getAxisGroup(fullLayout, pa._id) + firstTrace.orientation; + alignmentGroups = fullLayout._alignmentOpts[firstTrace.type][groupId] || {}; } for(var i = 0; i < nTraces; i++) { diff --git a/src/traces/box/cross_trace_calc.js b/src/traces/box/cross_trace_calc.js index 00632d0dbb2..4ce56f3c076 100644 --- a/src/traces/box/cross_trace_calc.js +++ b/src/traces/box/cross_trace_calc.js @@ -100,11 +100,14 @@ function setPositionOffset(traceType, gd, boxList, posAxis) { } else { dPos = dPos0; + var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation; + if(fullLayout._alignmentOpts[traceType] === undefined) { + fullLayout._alignmentOpts[traceType] = {}; + } + var alignmentGroups = fullLayout._alignmentOpts[traceType][groupId] || {}; + var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; + var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; if(group) { - var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation; - var alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; - var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; - var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; var num = nOffsetGroups || numTotal; var shift = nOffsetGroups ? trace._offsetIndex : t.num; diff --git a/src/traces/histogram/cross_trace_defaults.js b/src/traces/histogram/cross_trace_defaults.js index 7342360af0f..843dca4a6b5 100644 --- a/src/traces/histogram/cross_trace_defaults.js +++ b/src/traces/histogram/cross_trace_defaults.js @@ -116,8 +116,10 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { } } } - - var alignmentOpts = fullLayout._alignmentOpts || {}; + var alignmentOpts = {}; + if(fullLayout._alignmentOpts.histogram !== undefined) { + alignmentOpts = fullLayout._alignmentOpts.histogram || {}; + } // Look for traces that "have to match", that is: // - 1d histogram traces on the same subplot with same orientation under barmode:stack, @@ -136,7 +138,7 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { if(fullLayout.barmode === 'group' && traceOut.alignmentgroup) { var pa = traceOut[binDir + 'axis']; var aGroupId = getAxisGroup(fullLayout, pa) + traceOut.orientation; - if((alignmentOpts[aGroupId] || {})[traceOut.alignmentgroup]) { + if((alignmentOpts.histogram[aGroupId] || {})[traceOut.alignmentgroup]) { groupName = aGroupId; } } diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index 3c3f488ec86..0acc8588a40 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -8,7 +8,12 @@ module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, var posAxId = traceOut[{v: 'x', h: 'y'}[orientation] + 'axis']; var groupId = getAxisGroup(fullLayout, posAxId) + orientation; - var alignmentOpts = fullLayout._alignmentOpts || {}; + var allAlignmentOpts = fullLayout._alignmentOpts || {}; + if(allAlignmentOpts[traceOut.type] === undefined) { + allAlignmentOpts[traceOut.type] = {}; + } + var alignmentOpts = allAlignmentOpts[traceOut.type]; + var alignmentgroup = coerce('alignmentgroup'); var alignmentGroups = alignmentOpts[groupId]; From ac93f5d7079429b2ce367145294cbe06a521b609 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Fri, 7 Jun 2024 14:41:28 +0200 Subject: [PATCH 15/23] Make offsetgroup work for boxmode overlay as well --- src/traces/box/cross_trace_calc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/box/cross_trace_calc.js b/src/traces/box/cross_trace_calc.js index 4ce56f3c076..ff7f553c8f9 100644 --- a/src/traces/box/cross_trace_calc.js +++ b/src/traces/box/cross_trace_calc.js @@ -107,7 +107,7 @@ function setPositionOffset(traceType, gd, boxList, posAxis) { var alignmentGroups = fullLayout._alignmentOpts[traceType][groupId] || {}; var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; - if(group) { + if(group || nOffsetGroups) { var num = nOffsetGroups || numTotal; var shift = nOffsetGroups ? trace._offsetIndex : t.num; From e43227c6a6edeb03a462743a7c5957fa4a12a01d Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Fri, 7 Jun 2024 14:42:53 +0200 Subject: [PATCH 16/23] Documentation for setOffsetAndWidth and fix for sieve documentations --- src/traces/bar/cross_trace_calc.js | 12 ++++++++++++ src/traces/bar/sieve.js | 3 +++ 2 files changed, 15 insertions(+) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 74be462c37c..65aa365368a 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -300,6 +300,18 @@ function setGroupPositionsInStackOrRelativeMode(gd, pa, sa, calcTraces, opts) { if(opts.norm) normalizeBars(sa, sieve, opts); } +/** + * Mode group: Traces should be offsetted to other traces at the same position if they have a + * different offsetgroup or if no offsetgroups are specified. + * If there are no other traces at the same position, the trace will not be offsetted and it + * can occupy the whole width. + * If two traces share an offsetgroup, they should overlap. + * Mode overlay/stack/relative: Traces should be offseted to other traces at the same position if + * they have a different offsetgroup. + * If two traces share an offsetgroup or if no offsetgroups are specified, they should instead + * overlap/stack. + * Angular axes (for barpolar type) don't support group offsets. + */ function setOffsetAndWidth(gd, pa, sieve, opts) { var fullLayout = gd._fullLayout; var positions = sieve.positions; diff --git a/src/traces/bar/sieve.js b/src/traces/bar/sieve.js index 1368d34d345..1af738edff9 100644 --- a/src/traces/bar/sieve.js +++ b/src/traces/bar/sieve.js @@ -66,6 +66,7 @@ function Sieve(traces, opts) { * * @method * @param {number} position + * @param {number} group * @param {number} value * @returns {number} Previous bin value */ @@ -83,6 +84,7 @@ Sieve.prototype.put = function put(position, group, value) { * * @method * @param {number} position Position of datum + * @param {number} group * @param {number} [value] Value of datum * (required if this.sepNegVal is true) * @returns {number} Current bin value @@ -97,6 +99,7 @@ Sieve.prototype.get = function get(position, group, value) { * * @method * @param {number} position Position of datum + * @param {number} group * @param {number} [value] Value of datum * (required if this.sepNegVal is true) * @returns {string} Bin label From f08f9250f00410b71e1cf02c35223bcc67365f2a Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 28 Aug 2024 14:01:13 +0200 Subject: [PATCH 17/23] Revert "Make offsetgroup work for boxmode overlay as well" This reverts commit ac93f5d7079429b2ce367145294cbe06a521b609. --- src/traces/box/cross_trace_calc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/traces/box/cross_trace_calc.js b/src/traces/box/cross_trace_calc.js index ff7f553c8f9..4ce56f3c076 100644 --- a/src/traces/box/cross_trace_calc.js +++ b/src/traces/box/cross_trace_calc.js @@ -107,7 +107,7 @@ function setPositionOffset(traceType, gd, boxList, posAxis) { var alignmentGroups = fullLayout._alignmentOpts[traceType][groupId] || {}; var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; - if(group || nOffsetGroups) { + if(group) { var num = nOffsetGroups || numTotal; var shift = nOffsetGroups ? trace._offsetIndex : t.num; From d855f174dfcfd179fcc07c20c4db352caa0b7289 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 28 Aug 2024 14:01:20 +0200 Subject: [PATCH 18/23] Revert "Track alignmentgroups in fullLayout._alignmentOpts by trace type" This reverts commit e8bd5db9fb6cc42ecccf0108865816750c976d2d. --- src/traces/bar/cross_trace_calc.js | 5 ++--- src/traces/box/cross_trace_calc.js | 11 ++++------- src/traces/histogram/cross_trace_defaults.js | 8 +++----- src/traces/scatter/grouping_defaults.js | 7 +------ 4 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/traces/bar/cross_trace_calc.js b/src/traces/bar/cross_trace_calc.js index 65aa365368a..ea1757df2f1 100644 --- a/src/traces/bar/cross_trace_calc.js +++ b/src/traces/bar/cross_trace_calc.js @@ -334,9 +334,8 @@ function setOffsetAndWidth(gd, pa, sieve, opts) { barWidth = barWidthPlusGap * (1 - (opts.groupgap || 0)); offsetFromCenter = -barWidth / 2; } else { // collect groups and calculate values in loop below - var firstTrace = calcTraces[0][0].trace; - var groupId = getAxisGroup(fullLayout, pa._id) + firstTrace.orientation; - alignmentGroups = fullLayout._alignmentOpts[firstTrace.type][groupId] || {}; + var groupId = getAxisGroup(fullLayout, pa._id) + calcTraces[0][0].trace.orientation; + alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; } for(var i = 0; i < nTraces; i++) { diff --git a/src/traces/box/cross_trace_calc.js b/src/traces/box/cross_trace_calc.js index 4ce56f3c076..00632d0dbb2 100644 --- a/src/traces/box/cross_trace_calc.js +++ b/src/traces/box/cross_trace_calc.js @@ -100,14 +100,11 @@ function setPositionOffset(traceType, gd, boxList, posAxis) { } else { dPos = dPos0; - var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation; - if(fullLayout._alignmentOpts[traceType] === undefined) { - fullLayout._alignmentOpts[traceType] = {}; - } - var alignmentGroups = fullLayout._alignmentOpts[traceType][groupId] || {}; - var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; - var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; if(group) { + var groupId = getAxisGroup(fullLayout, posAxis._id) + trace.orientation; + var alignmentGroups = fullLayout._alignmentOpts[groupId] || {}; + var alignmentGroupOpts = alignmentGroups[trace.alignmentgroup] || {}; + var nOffsetGroups = Object.keys(alignmentGroupOpts.offsetGroups || {}).length; var num = nOffsetGroups || numTotal; var shift = nOffsetGroups ? trace._offsetIndex : t.num; diff --git a/src/traces/histogram/cross_trace_defaults.js b/src/traces/histogram/cross_trace_defaults.js index 843dca4a6b5..7342360af0f 100644 --- a/src/traces/histogram/cross_trace_defaults.js +++ b/src/traces/histogram/cross_trace_defaults.js @@ -116,10 +116,8 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { } } } - var alignmentOpts = {}; - if(fullLayout._alignmentOpts.histogram !== undefined) { - alignmentOpts = fullLayout._alignmentOpts.histogram || {}; - } + + var alignmentOpts = fullLayout._alignmentOpts || {}; // Look for traces that "have to match", that is: // - 1d histogram traces on the same subplot with same orientation under barmode:stack, @@ -138,7 +136,7 @@ module.exports = function crossTraceDefaults(fullData, fullLayout) { if(fullLayout.barmode === 'group' && traceOut.alignmentgroup) { var pa = traceOut[binDir + 'axis']; var aGroupId = getAxisGroup(fullLayout, pa) + traceOut.orientation; - if((alignmentOpts.histogram[aGroupId] || {})[traceOut.alignmentgroup]) { + if((alignmentOpts[aGroupId] || {})[traceOut.alignmentgroup]) { groupName = aGroupId; } } diff --git a/src/traces/scatter/grouping_defaults.js b/src/traces/scatter/grouping_defaults.js index 0acc8588a40..3c3f488ec86 100644 --- a/src/traces/scatter/grouping_defaults.js +++ b/src/traces/scatter/grouping_defaults.js @@ -8,12 +8,7 @@ module.exports = function handleGroupingDefaults(traceIn, traceOut, fullLayout, var posAxId = traceOut[{v: 'x', h: 'y'}[orientation] + 'axis']; var groupId = getAxisGroup(fullLayout, posAxId) + orientation; - var allAlignmentOpts = fullLayout._alignmentOpts || {}; - if(allAlignmentOpts[traceOut.type] === undefined) { - allAlignmentOpts[traceOut.type] = {}; - } - var alignmentOpts = allAlignmentOpts[traceOut.type]; - + var alignmentOpts = fullLayout._alignmentOpts || {}; var alignmentgroup = coerce('alignmentgroup'); var alignmentGroups = alignmentOpts[groupId]; From b3ac3c99b284c6be5aec1bb2e26babd02144eea8 Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 28 Aug 2024 14:57:33 +0200 Subject: [PATCH 19/23] Ignore offsetgroup and alignmentgroup for those trace types that don't have a mode "stack", i.e. scatter, box, violin, waterfall --- src/traces/box/defaults.js | 5 ++++- src/traces/scatter/cross_trace_defaults.js | 15 +++++++++------ src/traces/waterfall/defaults.js | 11 ++++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/traces/box/defaults.js b/src/traces/box/defaults.js index e9fdeb87c18..8241e0cb140 100644 --- a/src/traces/box/defaults.js +++ b/src/traces/box/defaults.js @@ -303,7 +303,10 @@ function crossTraceDefaults(fullData, fullLayout) { if(traceType === 'box' || traceType === 'violin') { traceIn = traceOut._input; - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout[traceType + 'mode']); + var mode = fullLayout[traceType + 'mode']; + if(mode === 'group') { + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, mode); + } } } } diff --git a/src/traces/scatter/cross_trace_defaults.js b/src/traces/scatter/cross_trace_defaults.js index 67eb2790e29..2b97dc39532 100644 --- a/src/traces/scatter/cross_trace_defaults.js +++ b/src/traces/scatter/cross_trace_defaults.js @@ -7,17 +7,20 @@ var attributes = require('./attributes'); // remove opacity for any trace that has a fill or is filled to module.exports = function crossTraceDefaults(fullData, fullLayout) { var traceIn, traceOut, i; + var scattermode = fullLayout.scattermode; function coerce(attr) { return Lib.coerce(traceOut._input, traceOut, attributes, attr); } - for(i = 0; i < fullData.length; i++) { - traceOut = fullData[i]; - - if(traceOut.type === 'scatter') { - traceIn = traceOut._input; - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.scattermode); + if(fullLayout.scattermode === 'group') { + for(i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; + + if(traceOut.type === 'scatter') { + traceIn = traceOut._input; + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, scattermode); + } } } diff --git a/src/traces/waterfall/defaults.js b/src/traces/waterfall/defaults.js index c6d62b69fc5..3df93af6f5d 100644 --- a/src/traces/waterfall/defaults.js +++ b/src/traces/waterfall/defaults.js @@ -85,12 +85,13 @@ function crossTraceDefaults(fullData, fullLayout) { function coerce(attr) { return Lib.coerce(traceOut._input, traceOut, attributes, attr); } + if(fullLayout.waterfallmode === 'group') { + for(var i = 0; i < fullData.length; i++) { + traceOut = fullData[i]; + traceIn = traceOut._input; - for(var i = 0; i < fullData.length; i++) { - traceOut = fullData[i]; - traceIn = traceOut._input; - - handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.waterfallmode); + handleGroupingDefaults(traceIn, traceOut, fullLayout, coerce, fullLayout.waterfallmode); + } } } From db602ab4227f390d17cfa2b3b25449c2dc19542c Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 2 Sep 2024 10:55:25 +0200 Subject: [PATCH 20/23] Update funnel test after adding support for alignmentgroup and offsetgroup for stackable traces --- test/jasmine/tests/funnel_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jasmine/tests/funnel_test.js b/test/jasmine/tests/funnel_test.js index b28642fe560..295eea9478d 100644 --- a/test/jasmine/tests/funnel_test.js +++ b/test/jasmine/tests/funnel_test.js @@ -244,7 +244,7 @@ describe('Funnel.supplyDefaults', function() { expect(traceOut.ycalendar).toBe('ethiopian'); }); - it('should not include alignementgroup/offsetgroup when funnelmode is not *group*', function() { + it('should include alignementgroup/offsetgroup regardless of the funnelmode', function() { var gd = { data: [{type: 'funnel', y: [1], alignmentgroup: 'a', offsetgroup: '1'}], layout: {funnelmode: 'group'} @@ -256,8 +256,8 @@ describe('Funnel.supplyDefaults', function() { gd.layout.funnelmode = 'stack'; supplyAllDefaults(gd); - expect(gd._fullData[0].alignmentgroup).toBe(undefined, 'alignementgroup'); - expect(gd._fullData[0].offsetgroup).toBe(undefined, 'offsetgroup'); + expect(gd._fullData[0].alignmentgroup).toBe('a', 'alignementgroup'); + expect(gd._fullData[0].offsetgroup).toBe('1', 'offsetgroup'); }); }); From 9f3624dc398474984f4e52a4dd28b11e56006d2a Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Mon, 2 Sep 2024 12:06:32 +0200 Subject: [PATCH 21/23] Update bar test after adding support for alignmentgroup and offsetgroup for stackable traces --- test/jasmine/tests/bar_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/jasmine/tests/bar_test.js b/test/jasmine/tests/bar_test.js index 4ddd88c65e8..fc6c5bb8c80 100644 --- a/test/jasmine/tests/bar_test.js +++ b/test/jasmine/tests/bar_test.js @@ -243,7 +243,7 @@ describe('Bar.supplyDefaults', function() { expect(traceOut.ycalendar).toBe('ethiopian'); }); - it('should not include alignmentgroup/offsetgroup when barmode is not *group*', function() { + it('should include alignmentgroup/offsetgroup regardless of barmode', function() { var gd = { data: [{type: 'bar', y: [1], alignmentgroup: 'a', offsetgroup: '1'}], layout: {barmode: 'group'} @@ -255,8 +255,8 @@ describe('Bar.supplyDefaults', function() { gd.layout.barmode = 'stack'; supplyAllDefaults(gd); - expect(gd._fullData[0].alignmentgroup).toBe(undefined, 'alignementgroup'); - expect(gd._fullData[0].offsetgroup).toBe(undefined, 'offsetgroup'); + expect(gd._fullData[0].alignmentgroup).toBe('a', 'alignementgroup'); + expect(gd._fullData[0].offsetgroup).toBe('1', 'offsetgroup'); }); it('should have a barmode only if it contains bars', function() { From 2059f807da6dbe5dd45f229f49b52477c98bb3bf Mon Sep 17 00:00:00 2001 From: My-Tien Nguyen Date: Wed, 4 Sep 2024 17:24:44 +0200 Subject: [PATCH 22/23] Update baseline images for legendgroup_bar-stack and funnel_attrs --- test/image/baselines/funnel_attrs.png | Bin 42407 -> 40425 bytes .../image/baselines/legendgroup_bar-stack.png | Bin 22175 -> 21076 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/test/image/baselines/funnel_attrs.png b/test/image/baselines/funnel_attrs.png index 7d951f1f448344854a63f2dc41b1da737917beb5..80e74a1ab55d6ca13d27733c45b05820460655c4 100644 GIT binary patch literal 40425 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 ZuK)0(fTKejp8f*9OpMI-J~y-v{x9L5!Ylv) literal 42407 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 From 5ad372b98c63de61b6dc4292872300485ce9570d Mon Sep 17 00:00:00 2001 From: Mojtaba Samimi Date: Tue, 22 Oct 2024 11:05:45 -0400 Subject: [PATCH 23/23] PR log --- draftlogs/7009_change.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 draftlogs/7009_change.md diff --git a/draftlogs/7009_change.md b/draftlogs/7009_change.md new file mode 100644 index 00000000000..f804cd26073 --- /dev/null +++ b/draftlogs/7009_change.md @@ -0,0 +1 @@ +- Make offsetgroup work with barmode 'stacked' and 'relative' for bar traces [[#7009](https://github.com/plotly/plotly.js/pull/7009)] \ No newline at end of file