Skip to content

Commit f9a15be

Browse files
authored
Merge pull request #2415 from plotly/parcoords-multiselect-squashed
multiple selections on parcoords axes
2 parents 6e0b63a + c3cc927 commit f9a15be

23 files changed

+2320
-1207
lines changed

src/lib/coerce.js

+18-7
Original file line numberDiff line numberDiff line change
@@ -260,9 +260,11 @@ exports.valObjectMeta = {
260260
'An {array} of plot information.'
261261
].join(' '),
262262
requiredOpts: ['items'],
263-
// set dimensions=2 for a 2D array
263+
// set `dimensions=2` for a 2D array or '1-2' for either
264264
// `items` may be a single object instead of an array, in which case
265265
// `freeLength` must be true.
266+
// if `dimensions='1-2'` and items is a 1D array, then the value can
267+
// either be a matching 1D array or an array of such matching 1D arrays
266268
otherOpts: ['dflt', 'freeLength', 'dimensions'],
267269
coerceFunction: function(v, propOut, dflt, opts) {
268270

@@ -278,7 +280,7 @@ exports.valObjectMeta = {
278280
return out;
279281
}
280282

281-
var twoD = opts.dimensions === 2;
283+
var twoD = opts.dimensions === 2 || (opts.dimensions === '1-2' && Array.isArray(v) && Array.isArray(v[0]));
282284

283285
if(!Array.isArray(v)) {
284286
propOut.set(dflt);
@@ -288,19 +290,28 @@ exports.valObjectMeta = {
288290
var items = opts.items;
289291
var vOut = [];
290292
var arrayItems = Array.isArray(items);
291-
var len = arrayItems ? items.length : v.length;
293+
var arrayItems2D = arrayItems && twoD && Array.isArray(items[0]);
294+
var innerItemsOnly = twoD && arrayItems && !arrayItems2D;
295+
var len = (arrayItems && !innerItemsOnly) ? items.length : v.length;
292296

293-
var i, j, len2, vNew;
297+
var i, j, row, item, len2, vNew;
294298

295299
dflt = Array.isArray(dflt) ? dflt : [];
296300

297301
if(twoD) {
298302
for(i = 0; i < len; i++) {
299303
vOut[i] = [];
300-
var row = Array.isArray(v[i]) ? v[i] : [];
301-
len2 = arrayItems ? items[i].length : row.length;
304+
row = Array.isArray(v[i]) ? v[i] : [];
305+
if(innerItemsOnly) len2 = items.length;
306+
else if(arrayItems) len2 = items[i].length;
307+
else len2 = row.length;
308+
302309
for(j = 0; j < len2; j++) {
303-
vNew = coercePart(row[j], arrayItems ? items[i][j] : items, (dflt[i] || [])[j]);
310+
if(innerItemsOnly) item = items[j];
311+
else if(arrayItems) item = items[i][j];
312+
else item = items;
313+
314+
vNew = coercePart(row[j], item, (dflt[i] || [])[j]);
304315
if(vNew !== undefined) vOut[i][j] = vNew;
305316
}
306317
}

src/traces/parcoords/attributes.js

+13-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ module.exports = {
4343
editType: 'calc',
4444
description: 'The shown name of the dimension.'
4545
},
46+
// TODO: better way to determine ordinal vs continuous axes,
47+
// so users can use tickvals/ticktext with a continuous axis.
4648
tickvals: extendFlat({}, axesAttrs.tickvals, {editType: 'calc'}),
4749
ticktext: extendFlat({}, axesAttrs.ticktext, {editType: 'calc'}),
4850
tickformat: {
@@ -79,16 +81,26 @@ module.exports = {
7981
constraintrange: {
8082
valType: 'info_array',
8183
role: 'info',
84+
freeLength: true,
85+
dimensions: '1-2',
8286
items: [
8387
{valType: 'number', editType: 'calc'},
8488
{valType: 'number', editType: 'calc'}
8589
],
8690
editType: 'calc',
8791
description: [
8892
'The domain range to which the filter on the dimension is constrained. Must be an array',
89-
'of `[fromValue, toValue]` with finite numbers as elements.'
93+
'of `[fromValue, toValue]` with `fromValue <= toValue`, or if `multiselect` is not',
94+
'disabled, you may give an array of arrays, where each inner array is `[fromValue, toValue]`.'
9095
].join(' ')
9196
},
97+
multiselect: {
98+
valType: 'boolean',
99+
dflt: true,
100+
role: 'info',
101+
editType: 'calc',
102+
description: 'Do we allow multiple selection ranges or just a single range?'
103+
},
92104
values: {
93105
valType: 'data_array',
94106
role: 'info',

0 commit comments

Comments
 (0)