Skip to content

Commit 7044a13

Browse files
committed
standardize transforms handling of _length
1 parent fcc459d commit 7044a13

File tree

6 files changed

+115
-18
lines changed

6 files changed

+115
-18
lines changed

src/transforms/aggregate.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,10 @@ exports.calcTransform = function(gd, trace, opts) {
224224

225225
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
226226

227-
for(i = 0; i < groupArray.length; i++) {
227+
var len = groupArray.length;
228+
if(trace._length) len = Math.min(len, trace._length);
229+
230+
for(i = 0; i < len; i++) {
228231
vi = groupArray[i];
229232
groupIndex = groupIndices[vi];
230233
if(groupIndex === undefined) {

src/transforms/filter.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,13 @@ exports.calcTransform = function(gd, trace, opts) {
158158
if(!targetArray) return;
159159

160160
var target = opts.target;
161+
161162
var len = targetArray.length;
163+
if(trace._length) len = Math.min(len, trace._length);
164+
162165
var targetCalendar = opts.targetcalendar;
163166
var arrayAttrs = trace._arrayAttrs;
167+
var preservegaps = opts.preservegaps;
164168

165169
// even if you provide targetcalendar, if target is a string and there
166170
// is a calendar attribute matching target it will get used instead.
@@ -184,7 +188,7 @@ exports.calcTransform = function(gd, trace, opts) {
184188

185189
var initFn;
186190
var fillFn;
187-
if(opts.preservegaps) {
191+
if(preservegaps) {
188192
initFn = function(np) {
189193
originalArrays[np.astr] = Lib.extendDeep([], np.get());
190194
np.set(new Array(len));
@@ -216,6 +220,7 @@ exports.calcTransform = function(gd, trace, opts) {
216220
forAllAttrs(fillFn, i);
217221
indexToPoints[index++] = originalPointsAccessor(i);
218222
}
223+
else if(preservegaps) index++;
219224
}
220225

221226
opts._indexToPoints = indexToPoints;

src/transforms/sort.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,13 @@ exports.calcTransform = function(gd, trace, opts) {
8484
if(!targetArray) return;
8585

8686
var target = opts.target;
87+
8788
var len = targetArray.length;
89+
if(trace._length) len = Math.min(len, trace._length);
90+
8891
var arrayAttrs = trace._arrayAttrs;
8992
var d2c = Axes.getDataToCoordFunc(gd, trace, target, targetArray);
90-
var indices = getIndices(opts, targetArray, d2c);
93+
var indices = getIndices(opts, targetArray, d2c, len);
9194
var originalPointsAccessor = pointsAccessorFunction(trace.transforms, opts);
9295
var indexToPoints = {};
9396
var i, j;
@@ -109,14 +112,14 @@ exports.calcTransform = function(gd, trace, opts) {
109112
}
110113

111114
opts._indexToPoints = indexToPoints;
115+
trace._length = len;
112116
};
113117

114-
function getIndices(opts, targetArray, d2c) {
115-
var len = targetArray.length;
118+
function getIndices(opts, targetArray, d2c, len) {
116119
var indices = new Array(len);
117120

118121
var sortedArray = targetArray
119-
.slice()
122+
.slice(0, len)
120123
.sort(getSortFunc(opts, d2c));
121124

122125
for(var i = 0; i < len; i++) {

test/jasmine/tests/transform_aggregate_test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,46 @@ describe('aggregate', function() {
257257
expect(traceOut.marker.color).toBeCloseToArray([Math.sqrt(1 / 3), 0], 5);
258258
});
259259

260+
it('handles ragged data - extra groups are ignored', function() {
261+
Plotly.newPlot(gd, [{
262+
x: [1, 1, 2, 2, 1, 3, 4],
263+
y: [1, 2, 3, 4, 5], // shortest array controls all
264+
transforms: [{
265+
type: 'aggregate',
266+
groups: [1, 2, 1, 1, 1, 3, 3, 4, 4, 5],
267+
aggregations: [
268+
{target: 'x', func: 'mode'},
269+
{target: 'y', func: 'median'},
270+
]
271+
}]
272+
}]);
273+
274+
var traceOut = gd._fullData[0];
275+
276+
expect(traceOut.x).toEqual([2, 1]);
277+
expect(traceOut.y).toBeCloseToArray([3.5, 2], 5);
278+
});
279+
280+
it('handles ragged data - groups is the shortest, others are ignored', function() {
281+
Plotly.newPlot(gd, [{
282+
x: [1, 1, 2, 2, 1, 3, 4],
283+
y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
284+
transforms: [{
285+
type: 'aggregate',
286+
groups: [1, 2, 1, 1, 1], // shortest array controls all
287+
aggregations: [
288+
{target: 'x', func: 'mode'},
289+
{target: 'y', func: 'median'},
290+
]
291+
}]
292+
}]);
293+
294+
var traceOut = gd._fullData[0];
295+
296+
expect(traceOut.x).toEqual([2, 1]);
297+
expect(traceOut.y).toBeCloseToArray([3.5, 2], 5);
298+
});
299+
260300
it('links fullData aggregations to userData via _index', function() {
261301
Plotly.newPlot(gd, [{
262302
x: [1, 2, 3, 4, 5],

test/jasmine/tests/transform_filter_test.js

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ describe('filter transforms calc:', function() {
365365
expect(out[0].x).toEqual([undefined, undefined, undefined, undefined, 1, 2, 3]);
366366
expect(out[0].y).toEqual([undefined, undefined, undefined, undefined, 2, 3, 1]);
367367
expect(out[0].marker.color).toEqual([undefined, undefined, undefined, undefined, 0.2, 0.3, 0.4]);
368+
expect(out[0].transforms[0]._indexToPoints).toEqual({4: [4], 5: [5], 6: [6]});
368369
});
369370

370371
it('two filter transforms with `preservegaps: true` should commute', function() {
@@ -391,6 +392,11 @@ describe('filter transforms calc:', function() {
391392
var out1 = _transform([Lib.extendDeep({}, base, {
392393
transforms: [transform1, transform0]
393394
})]);
395+
// _indexToPoints differs in the first transform but matches in the second
396+
expect(out0[0].transforms[0]._indexToPoints).toEqual({3: [3], 4: [4], 5: [5], 6: [6]});
397+
expect(out1[0].transforms[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [2], 3: [3], 4: [4]});
398+
expect(out0[0].transforms[1]._indexToPoints).toEqual({3: [3], 4: [4]});
399+
expect(out1[0].transforms[1]._indexToPoints).toEqual({3: [3], 4: [4]});
394400

395401
['x', 'y', 'ids', 'marker.color', 'marker.size'].forEach(function(k) {
396402
var v0 = Lib.nestedProperty(out0[0], k).get();
@@ -424,14 +430,20 @@ describe('filter transforms calc:', function() {
424430
transforms: [transform1, transform0]
425431
})]);
426432

433+
// _indexToPoints differs in the first transform but matches in the second
434+
expect(out0[0].transforms[0]._indexToPoints).toEqual({0: [3], 1: [4], 2: [5], 3: [6]});
435+
expect(out1[0].transforms[0]._indexToPoints).toEqual({0: [0], 1: [1], 2: [2], 3: [3], 4: [4]});
436+
expect(out0[0].transforms[1]._indexToPoints).toEqual({0: [3], 1: [4]});
437+
expect(out1[0].transforms[1]._indexToPoints).toEqual({0: [3], 1: [4]});
438+
427439
['x', 'y', 'ids', 'marker.color', 'marker.size'].forEach(function(k) {
428440
var v0 = Lib.nestedProperty(out0[0], k).get();
429441
var v1 = Lib.nestedProperty(out1[0], k).get();
430442
expect(v0).toEqual(v1);
431443
});
432444
});
433445

434-
it('two filter transforms with different `preservegaps` values should not necessary commute', function() {
446+
it('two filter transforms with different `preservegaps` values should not necessarily commute', function() {
435447
var transform0 = {
436448
type: 'filter',
437449
preservegaps: true,
@@ -872,6 +884,36 @@ describe('filter transforms calc:', function() {
872884
expect(out[0].transforms[0].target).toEqual([0, 0, 0]);
873885
});
874886

887+
it('with ragged items - longer target', function() {
888+
var out = _transform([Lib.extendDeep({}, _base, {
889+
transforms: [{
890+
target: [1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1],
891+
operation: '{}',
892+
value: 0
893+
}]
894+
})]);
895+
896+
_assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]);
897+
expect(out[0].transforms[0].target).toEqual([0, 0, 0]);
898+
});
899+
900+
it('with ragged items - longer data', function() {
901+
var out = _transform([Lib.extendDeep({}, _base, {
902+
x: _base.x.concat(_base.x),
903+
y: _base.y.concat(_base.y),
904+
ids: _base.ids.concat(['a1', 'a2', 'a3', 'a4']),
905+
marker: {color: _base.marker.color.concat(_base.marker.color)},
906+
transforms: [{
907+
target: [1, 1, 0, 0, 1, 0, 1],
908+
operation: '{}',
909+
value: 0
910+
}]
911+
})]);
912+
913+
_assert(out, [-2, 0, 2], [3, 1, 3], [0.3, 0.1, 0.3]);
914+
expect(out[0].transforms[0].target).toEqual([0, 0, 0]);
915+
});
916+
875917
it('with categorical items and *{}*', function() {
876918
var out = _transform([Lib.extendDeep({}, _base, {
877919
transforms: [{

test/jasmine/tests/transform_sort_test.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,14 @@ describe('Test sort transform calc:', function() {
214214
expect(out[0].ids).toEqual(['n1', 'n0']);
215215
expect(out[0].marker.color).toEqual([0.2, 0.1]);
216216
expect(out[0].marker.size).toEqual([20, 10]);
217+
expect(out[0]._length).toBe(2);
217218

218219
expect(out[1].x).toEqual([-2, -1]);
219220
expect(out[1].y).toEqual([1, 2]);
220221
expect(out[1].ids).toEqual(['n0', 'n1']);
221222
expect(out[1].marker.color).toEqual([0.1, 0.2]);
222223
expect(out[1].marker.size).toEqual([10, 20]);
224+
expect(out[1]._length).toBe(2);
223225
});
224226

225227
it('should truncate transformed arrays to target array length (long target case)', function() {
@@ -235,17 +237,19 @@ describe('Test sort transform calc:', function() {
235237
transforms: [{ target: 'text' }]
236238
})]);
237239

238-
expect(out[0].x).toEqual([1, undefined, -2, 3, undefined, -1, 1, undefined, -2, 0, undefined]);
239-
expect(out[0].y).toEqual([1, undefined, 3, 3, undefined, 2, 2, undefined, 1, 1, undefined]);
240-
expect(out[0].ids).toEqual(['p3', undefined, 'n2', 'p2', undefined, 'n1', 'p1', undefined, 'n0', 'z', undefined]);
241-
expect(out[0].marker.color).toEqual([0.4, undefined, 0.3, 0.3, undefined, 0.2, 0.2, undefined, 0.1, 0.1, undefined]);
242-
expect(out[0].marker.size).toEqual([10, undefined, 5, 0, undefined, 20, 6, undefined, 10, 1, undefined]);
243-
244-
expect(out[1].x).toEqual([-2, -1, -2, 0, 1, 3, 1, undefined, undefined]);
245-
expect(out[1].y).toEqual([1, 2, 3, 1, 2, 3, 1, undefined, undefined]);
246-
expect(out[1].ids).toEqual(['n0', 'n1', 'n2', 'z', 'p1', 'p2', 'p3', undefined, undefined]);
247-
expect(out[1].marker.color).toEqual([0.1, 0.2, 0.3, 0.1, 0.2, 0.3, 0.4, undefined, undefined]);
248-
expect(out[1].marker.size).toEqual([10, 20, 5, 1, 6, 0, 10, undefined, undefined]);
240+
expect(out[0].x).toEqual([1, -2, 3, -1, 1, -2, 0]);
241+
expect(out[0].y).toEqual([1, 3, 3, 2, 2, 1, 1]);
242+
expect(out[0].ids).toEqual(['p3', 'n2', 'p2', 'n1', 'p1', 'n0', 'z']);
243+
expect(out[0].marker.color).toEqual([0.4, 0.3, 0.3, 0.2, 0.2, 0.1, 0.1]);
244+
expect(out[0].marker.size).toEqual([10, 5, 0, 20, 6, 10, 1]);
245+
expect(out[0]._length).toBe(7);
246+
247+
expect(out[1].x).toEqual([-2, -1, -2, 0, 1, 3, 1]);
248+
expect(out[1].y).toEqual([1, 2, 3, 1, 2, 3, 1]);
249+
expect(out[1].ids).toEqual(['n0', 'n1', 'n2', 'z', 'p1', 'p2', 'p3']);
250+
expect(out[1].marker.color).toEqual([0.1, 0.2, 0.3, 0.1, 0.2, 0.3, 0.4]);
251+
expect(out[1].marker.size).toEqual([10, 20, 5, 1, 6, 0, 10]);
252+
expect(out[1]._length).toBe(7);
249253
});
250254
});
251255

0 commit comments

Comments
 (0)