Skip to content

Commit f617aef

Browse files
Merge pull request #2031 from plotly/aggregationInputIndicies
Add Aggregation user input _index
2 parents 2f2b300 + ec0a65f commit f617aef

File tree

3 files changed

+86
-19
lines changed

3 files changed

+86
-19
lines changed

src/plots/plots.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -1039,9 +1039,21 @@ plots.supplyTransformDefaults = function(traceIn, traceOut, layout) {
10391039
_module = transformsRegistry[type],
10401040
transformOut;
10411041

1042+
/*
1043+
* Supply defaults may run twice. First pass runs all supply defaults steps
1044+
* and adds the _module to any output transforms.
1045+
* If transforms exist another pass is run so that any generated traces also
1046+
* go through supply defaults. This has the effect of rerunning
1047+
* supplyTransformDefaults. If the transform does not have a `transform`
1048+
* function it could not have generated any new traces and the second stage
1049+
* is unnecessary. We detect this case with the following variables.
1050+
*/
1051+
var isFirstStage = !(transformIn._module && transformIn._module === _module),
1052+
doLaterStages = _module && typeof _module.transform === 'function';
1053+
10421054
if(!_module) Lib.warn('Unrecognized transform type ' + type + '.');
10431055

1044-
if(_module && _module.supplyDefaults) {
1056+
if(_module && _module.supplyDefaults && (isFirstStage || doLaterStages)) {
10451057
transformOut = _module.supplyDefaults(transformIn, traceOut, layout, traceIn);
10461058
transformOut.type = type;
10471059
transformOut._module = _module;

src/transforms/aggregate.js

+17-18
Original file line numberDiff line numberDiff line change
@@ -166,31 +166,29 @@ exports.supplyDefaults = function(transformIn, traceOut) {
166166
arrayAttrs[groups] = 0;
167167
}
168168

169-
var aggregationsIn = transformIn.aggregations;
169+
var aggregationsIn = transformIn.aggregations || [];
170170
var aggregationsOut = transformOut.aggregations = new Array(aggregationsIn.length);
171171
var aggregationOut;
172172

173173
function coercei(attr, dflt) {
174174
return Lib.coerce(aggregationsIn[i], aggregationOut, aggAttrs, attr, dflt);
175175
}
176176

177-
if(aggregationsIn) {
178-
for(i = 0; i < aggregationsIn.length; i++) {
179-
aggregationOut = {};
180-
var target = coercei('target');
181-
var func = coercei('func');
182-
var enabledi = coercei('enabled');
183-
184-
// add this aggregation to the output only if it's the first instance
185-
// of a valid target attribute - or an unused target attribute with "count"
186-
if(enabledi && target && (arrayAttrs[target] || (func === 'count' && arrayAttrs[target] === undefined))) {
187-
if(func === 'stddev') coercei('funcmode');
188-
189-
arrayAttrs[target] = 0;
190-
aggregationsOut[i] = aggregationOut;
191-
}
192-
else aggregationsOut[i] = {enabled: false};
177+
for(i = 0; i < aggregationsIn.length; i++) {
178+
aggregationOut = {_index: i};
179+
var target = coercei('target');
180+
var func = coercei('func');
181+
var enabledi = coercei('enabled');
182+
183+
// add this aggregation to the output only if it's the first instance
184+
// of a valid target attribute - or an unused target attribute with "count"
185+
if(enabledi && target && (arrayAttrs[target] || (func === 'count' && arrayAttrs[target] === undefined))) {
186+
if(func === 'stddev') coercei('funcmode');
187+
188+
arrayAttrs[target] = 0;
189+
aggregationsOut[i] = aggregationOut;
193190
}
191+
else aggregationsOut[i] = {enabled: false, _index: i};
194192
}
195193

196194
// any array attributes we haven't yet covered, fill them with the default aggregation
@@ -199,7 +197,8 @@ exports.supplyDefaults = function(transformIn, traceOut) {
199197
aggregationsOut.push({
200198
target: arrayAttrArray[i],
201199
func: aggAttrs.func.dflt,
202-
enabled: true
200+
enabled: true,
201+
_index: -1
203202
});
204203
}
205204
}

test/jasmine/tests/transform_aggregate_test.js

+56
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,26 @@ describe('aggregate', function() {
187187
expect(traceOut.marker.size).toEqual([10, 20]);
188188
});
189189

190+
// Regression test - throws before fix:
191+
// https://github.com/plotly/plotly.js/issues/2024
192+
it('can handle case where aggregation array is missing', function() {
193+
Plotly.newPlot(gd, [{
194+
x: [1, 2, 3, 4, 5],
195+
y: [2, 4, 6, 8, 10],
196+
marker: {size: [10, 10, 20, 20, 10]},
197+
transforms: [{
198+
type: 'aggregate',
199+
groups: 'marker.size'
200+
}]
201+
}]);
202+
203+
var traceOut = gd._fullData[0];
204+
205+
expect(traceOut.x).toEqual([1, 3]);
206+
expect(traceOut.y).toEqual([2, 6]);
207+
expect(traceOut.marker.size).toEqual([10, 20]);
208+
});
209+
190210
it('handles median, mode, rms, & stddev for numeric data', function() {
191211
// again, nothing is going to barf with non-numeric data, but sometimes it
192212
// won't make much sense.
@@ -222,4 +242,40 @@ describe('aggregate', function() {
222242
expect(traceOut.marker.line.width).toBeCloseToArray([0.5, 0], 5);
223243
expect(traceOut.marker.color).toBeCloseToArray([Math.sqrt(1 / 3), 0], 5);
224244
});
245+
246+
it('links fullData aggregations to userData via _index', function() {
247+
Plotly.newPlot(gd, [{
248+
x: [1, 2, 3, 4, 5],
249+
y: [2, 4, 6, 8, 10],
250+
marker: {
251+
size: [10, 10, 20, 20, 10],
252+
color: ['red', 'green', 'blue', 'yellow', 'white']
253+
},
254+
transforms: [{
255+
type: 'aggregate',
256+
groups: 'marker.size',
257+
aggregations: [
258+
{target: 'x', func: 'sum'},
259+
{target: 'x', func: 'avg'},
260+
{target: 'y', func: 'avg'},
261+
]
262+
}]
263+
}]);
264+
265+
var traceOut = gd._fullData[0];
266+
var fullAggregation = traceOut.transforms[0];
267+
var fullAggregations = fullAggregation.aggregations;
268+
var enabledAggregations = fullAggregations.filter(function(agg) {
269+
return agg.enabled;
270+
});
271+
272+
expect(enabledAggregations[0].target).toEqual('x');
273+
expect(enabledAggregations[0]._index).toEqual(0);
274+
275+
expect(enabledAggregations[1].target).toEqual('y');
276+
expect(enabledAggregations[1]._index).toEqual(2);
277+
278+
expect(enabledAggregations[2].target).toEqual('marker.color');
279+
expect(enabledAggregations[2]._index).toEqual(-1);
280+
});
225281
});

0 commit comments

Comments
 (0)