From b0923674d351a5e9417eafed83be0fc23303b1e3 Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 11 Oct 2016 14:54:17 -0400 Subject: [PATCH 1/3] Add grouping property to scatter traces --- src/traces/scatter/attributes.js | 14 +++++++++++++- src/traces/scatter/calc.js | 10 +++++++++- src/traces/scatter/defaults.js | 1 + src/transforms/filter.js | 6 ++++-- test/jasmine/tests/calcdata_test.js | 22 ++++++++++++++++++++++ 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index d9f83dd78ce..58d6614159b 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -67,7 +67,19 @@ module.exports = { }, ids: { valType: 'data_array', - description: 'A list of keys for object constancy of data points during animation' + description: [ + 'A list of unique string ids for object constancy of data points during animation.' + + 'For efficiency, the uniqueness of ids is not validated, but unexpected results may' + + 'occur if ids are not unique. *ids* is equivalent to a *key* in d3.' + ].join(' ') + }, + grouping: { + valType: 'data_array', + description: [ + 'An array of strings corresponding to each respective point. These strings are not' + + 'inherently used by plotly for any purpose but may be used, for example, with transforms' + + 'in order to filter or group points by an auxilliary property' + ].join(' ') }, text: { valType: 'string', diff --git a/src/traces/scatter/calc.js b/src/traces/scatter/calc.js index e7df798f1fd..9ce9aef9b8d 100644 --- a/src/traces/scatter/calc.js +++ b/src/traces/scatter/calc.js @@ -117,7 +117,15 @@ module.exports = function calc(gd, trace) { {x: x[i], y: y[i]} : {x: false, y: false}; if(trace.ids) { - cd[i].id = String(trace.ids[i]); + if(trace.ids[i] !== undefined && trace.ids[i] !== null) { + cd[i].id = String(trace.ids[i]); + } + } + + if(trace.grouping) { + if(trace.grouping[i] !== undefined && trace.grouping[i] !== null) { + cd[i].grouping = String(trace.grouping[i]); + } } } diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js index 115ef4c757e..a1085061aa8 100644 --- a/src/traces/scatter/defaults.js +++ b/src/traces/scatter/defaults.js @@ -39,6 +39,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('mode', defaultMode); coerce('ids'); + coerce('grouping'); if(subTypes.hasLines(traceOut)) { handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce); diff --git a/src/transforms/filter.js b/src/transforms/filter.js index 042798ac4ef..35494783e52 100644 --- a/src/transforms/filter.js +++ b/src/transforms/filter.js @@ -164,9 +164,11 @@ function getDataToCoordFunc(gd, trace, filtersrc) { // -> use setConvert method if(ax) return ax.d2c; - // special case for 'ids' + // special case for 'ids' or 'grouping' // -> cast to String - if(filtersrc === 'ids') return function(v) { return String(v); }; + if(['ids', 'grouping'].indexOf(filtersrc) !== -1) return function(v) { + return v === undefined ? undefined : String(v); + }; // otherwise // -> cast to Number diff --git a/test/jasmine/tests/calcdata_test.js b/test/jasmine/tests/calcdata_test.js index 9ac9dda0e98..babbacaa589 100644 --- a/test/jasmine/tests/calcdata_test.js +++ b/test/jasmine/tests/calcdata_test.js @@ -30,6 +30,28 @@ describe('calculated data and points', function() { }); }); + describe('ids', function() { + it('should assign ids to points and cast them to strings in the process', function() { + Plotly.plot(gd, [{ x: [1, 2, 3, 5], y: [1, null, 3, 5], ids: [1, 'a', 'b', undefined]}], {}); + + expect(gd.calcdata[0][0]).toEqual(jasmine.objectContaining({ x: 1, y: 1, id: '1'})); + expect(gd.calcdata[0][1]).toEqual(jasmine.objectContaining({ x: false, y: false, id: 'a'})); + expect(gd.calcdata[0][2]).toEqual(jasmine.objectContaining({ x: 3, y: 3, id: 'b'})); + expect(gd.calcdata[0][3]).toEqual(jasmine.objectContaining({ x: 5, y: 5})); + }); + }); + + describe('grouping', function() { + it('should assign grouping to points and cast them to strings in the process', function() { + Plotly.plot(gd, [{ x: [1, 2, 3, 5], y: [1, null, 3, 5], grouping: [1, 'a', 'b', undefined]}], {}); + + expect(gd.calcdata[0][0]).toEqual(jasmine.objectContaining({ x: 1, y: 1, grouping: '1'})); + expect(gd.calcdata[0][1]).toEqual(jasmine.objectContaining({ x: false, y: false, grouping: 'a'})); + expect(gd.calcdata[0][2]).toEqual(jasmine.objectContaining({ x: 3, y: 3, grouping: 'b'})); + expect(gd.calcdata[0][3]).toEqual(jasmine.objectContaining({ x: 5, y: 5})); + }); + }); + describe('category ordering', function() { describe('default category ordering reified', function() { From 56432c1f105d3ace4cedfedfbb2f8ff5d411e24e Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 11 Oct 2016 15:07:54 -0400 Subject: [PATCH 2/3] Fix lint error --- src/transforms/filter.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/transforms/filter.js b/src/transforms/filter.js index 35494783e52..bcf0e0f1679 100644 --- a/src/transforms/filter.js +++ b/src/transforms/filter.js @@ -166,9 +166,11 @@ function getDataToCoordFunc(gd, trace, filtersrc) { // special case for 'ids' or 'grouping' // -> cast to String - if(['ids', 'grouping'].indexOf(filtersrc) !== -1) return function(v) { - return v === undefined ? undefined : String(v); - }; + if(['ids', 'grouping'].indexOf(filtersrc) !== -1) { + return function(v) { + return v === undefined ? undefined : String(v); + }; + } // otherwise // -> cast to Number From b5f6833f6af169572a723ef7f086d913dd3096af Mon Sep 17 00:00:00 2001 From: Ricky Reusser Date: Tue, 18 Oct 2016 17:34:08 -0400 Subject: [PATCH 3/3] Start reorganizing grouping -> groups --- src/plots/attributes.js | 8 ++++++++ src/plots/plots.js | 1 + src/traces/scatter/attributes.js | 8 -------- src/traces/scatter/calc.js | 6 ------ src/traces/scatter/defaults.js | 1 - src/transforms/filter.js | 4 ++-- test/jasmine/tests/calcdata_test.js | 11 ----------- 7 files changed, 11 insertions(+), 28 deletions(-) diff --git a/src/plots/attributes.js b/src/plots/attributes.js index 69496df0ee3..e8f9d6f717f 100644 --- a/src/plots/attributes.js +++ b/src/plots/attributes.js @@ -28,6 +28,14 @@ module.exports = { '(provided that the legend itself is visible).' ].join(' ') }, + groups: { + valType: 'data_array', + description: [ + 'An array of strings corresponding to each respective datum. These strings are not' + + 'inherently used by plotly for any purpose but may be used, for example, with transforms' + + 'in order to filter or group points by an auxilliary property.' + ].join(' ') + }, showlegend: { valType: 'boolean', role: 'info', diff --git a/src/plots/plots.js b/src/plots/plots.js index 56aa8a9b696..13b5ddeceb7 100644 --- a/src/plots/plots.js +++ b/src/plots/plots.js @@ -742,6 +742,7 @@ plots.supplyTraceDefaults = function(traceIn, traceIndex, layout) { coerce('type'); coerce('uid'); coerce('name', 'trace ' + traceIndex); + coerce('groups'); // coerce subplot attributes of all registered subplot types var subplotTypes = Object.keys(subplotsRegistry); diff --git a/src/traces/scatter/attributes.js b/src/traces/scatter/attributes.js index 58d6614159b..dbc7b15cd36 100644 --- a/src/traces/scatter/attributes.js +++ b/src/traces/scatter/attributes.js @@ -73,14 +73,6 @@ module.exports = { 'occur if ids are not unique. *ids* is equivalent to a *key* in d3.' ].join(' ') }, - grouping: { - valType: 'data_array', - description: [ - 'An array of strings corresponding to each respective point. These strings are not' + - 'inherently used by plotly for any purpose but may be used, for example, with transforms' + - 'in order to filter or group points by an auxilliary property' - ].join(' ') - }, text: { valType: 'string', role: 'info', diff --git a/src/traces/scatter/calc.js b/src/traces/scatter/calc.js index 9ce9aef9b8d..cc91bdd14d6 100644 --- a/src/traces/scatter/calc.js +++ b/src/traces/scatter/calc.js @@ -121,12 +121,6 @@ module.exports = function calc(gd, trace) { cd[i].id = String(trace.ids[i]); } } - - if(trace.grouping) { - if(trace.grouping[i] !== undefined && trace.grouping[i] !== null) { - cd[i].grouping = String(trace.grouping[i]); - } - } } // this has migrated up from arraysToCalcdata as we have a reference to 's' here diff --git a/src/traces/scatter/defaults.js b/src/traces/scatter/defaults.js index a1085061aa8..115ef4c757e 100644 --- a/src/traces/scatter/defaults.js +++ b/src/traces/scatter/defaults.js @@ -39,7 +39,6 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout coerce('text'); coerce('mode', defaultMode); coerce('ids'); - coerce('grouping'); if(subTypes.hasLines(traceOut)) { handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce); diff --git a/src/transforms/filter.js b/src/transforms/filter.js index bcf0e0f1679..8699a16684f 100644 --- a/src/transforms/filter.js +++ b/src/transforms/filter.js @@ -164,9 +164,9 @@ function getDataToCoordFunc(gd, trace, filtersrc) { // -> use setConvert method if(ax) return ax.d2c; - // special case for 'ids' or 'grouping' + // special case for 'ids' or 'groups' // -> cast to String - if(['ids', 'grouping'].indexOf(filtersrc) !== -1) { + if(['ids', 'groups'].indexOf(filtersrc) !== -1) { return function(v) { return v === undefined ? undefined : String(v); }; diff --git a/test/jasmine/tests/calcdata_test.js b/test/jasmine/tests/calcdata_test.js index babbacaa589..b4ee7ffd0ee 100644 --- a/test/jasmine/tests/calcdata_test.js +++ b/test/jasmine/tests/calcdata_test.js @@ -41,17 +41,6 @@ describe('calculated data and points', function() { }); }); - describe('grouping', function() { - it('should assign grouping to points and cast them to strings in the process', function() { - Plotly.plot(gd, [{ x: [1, 2, 3, 5], y: [1, null, 3, 5], grouping: [1, 'a', 'b', undefined]}], {}); - - expect(gd.calcdata[0][0]).toEqual(jasmine.objectContaining({ x: 1, y: 1, grouping: '1'})); - expect(gd.calcdata[0][1]).toEqual(jasmine.objectContaining({ x: false, y: false, grouping: 'a'})); - expect(gd.calcdata[0][2]).toEqual(jasmine.objectContaining({ x: 3, y: 3, grouping: 'b'})); - expect(gd.calcdata[0][3]).toEqual(jasmine.objectContaining({ x: 5, y: 5})); - }); - }); - describe('category ordering', function() { describe('default category ordering reified', function() {