Skip to content

Commit 3d383b7

Browse files
authored
Merge pull request #3966 from plotly/refactor-parcoords-bug-fixes-labelangle-side
Refactor parcoords - bug fixes - reuse axes ticktext - support pseudo html labels - features for label angle & position
2 parents a6393bc + 2228339 commit 3d383b7

37 files changed

+4457
-626
lines changed

src/traces/parcoords/attributes.js

+46-26
Original file line numberDiff line numberDiff line change
@@ -17,68 +17,88 @@ var extendFlat = require('../../lib/extend').extendFlat;
1717
var templatedArray = require('../../plot_api/plot_template').templatedArray;
1818

1919
module.exports = {
20-
domain: domainAttrs({name: 'parcoords', trace: true, editType: 'calc'}),
20+
domain: domainAttrs({name: 'parcoords', trace: true, editType: 'plot'}),
21+
22+
labelangle: {
23+
valType: 'angle',
24+
dflt: 0,
25+
role: 'info',
26+
editType: 'plot',
27+
description: [
28+
'Sets the angle of the labels with respect to the horizontal.',
29+
'For example, a `tickangle` of -90 draws the labels vertically.',
30+
'Tilted labels with *labelangle* may be positioned better',
31+
'inside margins when `labelposition` is set to *bottom*.'
32+
].join(' ')
33+
},
34+
35+
labelside: {
36+
valType: 'enumerated',
37+
role: 'info',
38+
values: ['top', 'bottom'],
39+
dflt: 'top',
40+
editType: 'plot',
41+
description: [
42+
'Specifies the location of the `label`.',
43+
'*top* positions labels above, next to the title',
44+
'*bottom* positions labels below the graph',
45+
'Tilted labels with *labelangle* may be positioned better',
46+
'inside margins when `labelposition` is set to *bottom*.'
47+
].join(' ')
48+
},
2149

2250
labelfont: fontAttrs({
23-
editType: 'calc',
51+
editType: 'plot',
2452
description: 'Sets the font for the `dimension` labels.'
2553
}),
2654
tickfont: fontAttrs({
27-
editType: 'calc',
55+
editType: 'plot',
2856
description: 'Sets the font for the `dimension` tick values.'
2957
}),
3058
rangefont: fontAttrs({
31-
editType: 'calc',
59+
editType: 'plot',
3260
description: 'Sets the font for the `dimension` range values.'
3361
}),
3462

3563
dimensions: templatedArray('dimension', {
3664
label: {
3765
valType: 'string',
3866
role: 'info',
39-
editType: 'calc',
67+
editType: 'plot',
4068
description: 'The shown name of the dimension.'
4169
},
4270
// TODO: better way to determine ordinal vs continuous axes,
4371
// so users can use tickvals/ticktext with a continuous axis.
4472
tickvals: extendFlat({}, axesAttrs.tickvals, {
45-
editType: 'calc',
73+
editType: 'plot',
4674
description: [
4775
'Sets the values at which ticks on this axis appear.'
4876
].join(' ')
4977
}),
5078
ticktext: extendFlat({}, axesAttrs.ticktext, {
51-
editType: 'calc',
79+
editType: 'plot',
5280
description: [
5381
'Sets the text displayed at the ticks position via `tickvals`.'
5482
].join(' ')
5583
}),
56-
tickformat: {
57-
valType: 'string',
58-
dflt: '3s',
59-
role: 'style',
60-
editType: 'calc',
61-
description: [
62-
'Sets the tick label formatting rule using d3 formatting mini-language',
63-
'which is similar to those of Python. See',
64-
'https://github.com/d3/d3-format/blob/master/README.md#locale_format'
65-
].join(' ')
66-
},
84+
tickformat: extendFlat({}, axesAttrs.tickformat, {
85+
editType: 'plot'
86+
}),
6787
visible: {
6888
valType: 'boolean',
6989
dflt: true,
7090
role: 'info',
71-
editType: 'calc',
91+
editType: 'plot',
7292
description: 'Shows the dimension when set to `true` (the default). Hides the dimension for `false`.'
7393
},
7494
range: {
7595
valType: 'info_array',
7696
role: 'info',
7797
items: [
78-
{valType: 'number', editType: 'calc'},
79-
{valType: 'number', editType: 'calc'}
98+
{valType: 'number', editType: 'plot'},
99+
{valType: 'number', editType: 'plot'}
80100
],
81-
editType: 'calc',
101+
editType: 'plot',
82102
description: [
83103
'The domain range that represents the full, shown axis extent. Defaults to the `values` extent.',
84104
'Must be an array of `[fromValue, toValue]` with finite numbers as elements.'
@@ -90,10 +110,10 @@ module.exports = {
90110
freeLength: true,
91111
dimensions: '1-2',
92112
items: [
93-
{valType: 'number', editType: 'calc'},
94-
{valType: 'number', editType: 'calc'}
113+
{valType: 'number', editType: 'plot'},
114+
{valType: 'number', editType: 'plot'}
95115
],
96-
editType: 'calc',
116+
editType: 'plot',
97117
description: [
98118
'The domain range to which the filter on the dimension is constrained. Must be an array',
99119
'of `[fromValue, toValue]` with `fromValue <= toValue`, or if `multiselect` is not',
@@ -104,7 +124,7 @@ module.exports = {
104124
valType: 'boolean',
105125
dflt: true,
106126
role: 'info',
107-
editType: 'calc',
127+
editType: 'plot',
108128
description: 'Do we allow multiple selection ranges or just a single range?'
109129
},
110130
values: {

src/traces/parcoords/axisbrush.js

+9-1
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ function getBrushExtent(brush) {
419419

420420
function brushClear(brush) {
421421
brush.filterSpecified = false;
422-
brush.svgBrush.extent = [[0, 1]];
422+
brush.svgBrush.extent = [[-Infinity, Infinity]];
423423
}
424424

425425
function axisBrushMoved(callback) {
@@ -458,6 +458,14 @@ function makeFilter() {
458458
filter = a
459459
.map(function(d) { return d.slice().sort(sortAsc); })
460460
.sort(startAsc);
461+
462+
// handle unselected case
463+
if(filter.length === 1 &&
464+
filter[0][0] === -Infinity &&
465+
filter[0][1] === Infinity) {
466+
filter = [[0, -1]];
467+
}
468+
461469
consolidated = dedupeRealRanges(filter);
462470
bounds = filter.reduce(function(p, n) {
463471
return [Math.min(p[0], n[0]), Math.max(p[1], n[1])];

src/traces/parcoords/base_plot.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,16 @@ var getModuleCalcData = require('../../plots/get_data').getModuleCalcData;
1313
var parcoordsPlot = require('./plot');
1414
var xmlnsNamespaces = require('../../constants/xmlns_namespaces');
1515

16-
var PARCOORDS = 'parcoords';
17-
18-
exports.name = PARCOORDS;
16+
exports.name = 'parcoords';
1917

2018
exports.plot = function(gd) {
21-
var calcData = getModuleCalcData(gd.calcdata, PARCOORDS)[0];
19+
var calcData = getModuleCalcData(gd.calcdata, 'parcoords')[0];
2220
if(calcData.length) parcoordsPlot(gd, calcData);
2321
};
2422

2523
exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) {
26-
var hadParcoords = (oldFullLayout._has && oldFullLayout._has(PARCOORDS));
27-
var hasParcoords = (newFullLayout._has && newFullLayout._has(PARCOORDS));
24+
var hadParcoords = (oldFullLayout._has && oldFullLayout._has('parcoords'));
25+
var hasParcoords = (newFullLayout._has && newFullLayout._has('parcoords'));
2826

2927
if(hadParcoords && !hasParcoords) {
3028
oldFullLayout._paperdiv.selectAll('.parcoords').remove();

src/traces/parcoords/calc.js

+2-11
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,15 @@
88

99
'use strict';
1010

11+
var isArrayOrTypedArray = require('../../lib').isArrayOrTypedArray;
1112
var Colorscale = require('../../components/colorscale');
12-
var Lib = require('../../lib');
1313
var wrap = require('../../lib/gup').wrap;
1414

1515
module.exports = function calc(gd, trace) {
16-
for(var i = 0; i < trace.dimensions.length; i++) {
17-
trace.dimensions[i].values = convertTypedArray(trace.dimensions[i].values);
18-
}
19-
trace.line.color = convertTypedArray(trace.line.color);
20-
2116
var lineColor;
2217
var cscale;
2318

24-
if(Colorscale.hasColorscale(trace, 'line') && Array.isArray(trace.line.color)) {
19+
if(Colorscale.hasColorscale(trace, 'line') && isArrayOrTypedArray(trace.line.color)) {
2520
lineColor = trace.line.color;
2621
cscale = Colorscale.extractOpts(trace.line).colorscale;
2722

@@ -45,7 +40,3 @@ function constHalf(len) {
4540
}
4641
return out;
4742
}
48-
49-
function convertTypedArray(a) {
50-
return Lib.isTypedArray(a) ? Array.prototype.slice.call(a) : a;
51-
}

src/traces/parcoords/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module.exports = {
1919
layers: ['contextLineLayer', 'focusLineLayer', 'pickLineLayer'],
2020
axisTitleOffset: 28,
2121
axisExtentOffset: 10,
22+
deselectedLineColor: '#777',
2223
bar: {
2324
width: 4, // Visible width of the filter bar
2425
captureWidth: 10, // Mouse-sensitive width for interaction (Fitts law)

src/traces/parcoords/defaults.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var hasColorscale = require('../../components/colorscale/helpers').hasColorscale
1313
var colorscaleDefaults = require('../../components/colorscale/defaults');
1414
var handleDomainDefaults = require('../../plots/domain').defaults;
1515
var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
16+
var Axes = require('../../plots/cartesian/axes');
1617

1718
var attributes = require('./attributes');
1819
var axisBrush = require('./axisbrush');
@@ -37,7 +38,7 @@ function handleLineDefaults(traceIn, traceOut, defaultColor, layout, coerce) {
3738
return Infinity;
3839
}
3940

40-
function dimensionDefaults(dimensionIn, dimensionOut) {
41+
function dimensionDefaults(dimensionIn, dimensionOut, parentOut, opts) {
4142
function coerce(attr, dflt) {
4243
return Lib.coerce(dimensionIn, dimensionOut, attributes.dimensions, attr, dflt);
4344
}
@@ -53,7 +54,17 @@ function dimensionDefaults(dimensionIn, dimensionOut) {
5354
coerce('tickvals');
5455
coerce('ticktext');
5556
coerce('tickformat');
56-
coerce('range');
57+
var range = coerce('range');
58+
59+
dimensionOut._ax = {
60+
_id: 'y',
61+
type: 'linear',
62+
showexponent: 'all',
63+
exponentformat: 'B',
64+
range: range
65+
};
66+
67+
Axes.setConvert(dimensionOut._ax, opts.layout);
5768

5869
coerce('multiselect');
5970
var constraintRange = coerce('constraintrange');
@@ -76,6 +87,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
7687

7788
var dimensions = handleArrayContainerDefaults(traceIn, traceOut, {
7889
name: 'dimensions',
90+
layout: layout,
7991
handleItemDefaults: dimensionDefaults
8092
});
8193

@@ -100,4 +112,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
100112
Lib.coerceFont(coerce, 'labelfont', fontDflt);
101113
Lib.coerceFont(coerce, 'tickfont', fontDflt);
102114
Lib.coerceFont(coerce, 'rangefont', fontDflt);
115+
116+
coerce('labelangle');
117+
coerce('labelside');
103118
};

src/traces/parcoords/helpers.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright 2012-2019, Plotly, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the MIT license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
'use strict';
10+
11+
var isTypedArray = require('../../lib').isTypedArray;
12+
13+
exports.convertTypedArray = function(a) {
14+
return isTypedArray(a) ? Array.prototype.slice.call(a) : a;
15+
};
16+
17+
exports.isOrdinal = function(dimension) {
18+
return !!dimension.tickvals;
19+
};
20+
21+
exports.isVisible = function(dimension) {
22+
return dimension.visible || !('visible' in dimension);
23+
};

0 commit comments

Comments
 (0)