-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
parcoords #1256
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
parcoords #1256
Changes from all commits
59ff86d
e2621d0
32ed2d2
ded8f66
edffa6e
7005671
0d65012
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* Copyright 2012-2017, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
module.exports = require('../src/traces/parcoords'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
/** | ||
* Copyright 2012-2017, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
var colorAttributes = require('../../components/colorscale/color_attributes'); | ||
var colorbarAttrs = require('../../components/colorbar/attributes'); | ||
var colorscales = require('../../components/colorscale/scales'); | ||
var axesAttrs = require('../../plots/cartesian/layout_attributes'); | ||
|
||
var extendDeep = require('../../lib/extend').extendDeep; | ||
var extendFlat = require('../../lib/extend').extendFlat; | ||
|
||
module.exports = { | ||
|
||
domain: { | ||
x: { | ||
valType: 'info_array', | ||
role: 'info', | ||
items: [ | ||
{valType: 'number', min: 0, max: 1}, | ||
{valType: 'number', min: 0, max: 1} | ||
], | ||
dflt: [0, 1], | ||
description: [ | ||
'Sets the horizontal domain of this `parcoords` trace', | ||
'(in plot fraction).' | ||
].join(' ') | ||
}, | ||
y: { | ||
valType: 'info_array', | ||
role: 'info', | ||
items: [ | ||
{valType: 'number', min: 0, max: 1}, | ||
{valType: 'number', min: 0, max: 1} | ||
], | ||
dflt: [0, 1], | ||
description: [ | ||
'Sets the vertical domain of this `parcoords` trace', | ||
'(in plot fraction).' | ||
].join(' ') | ||
} | ||
}, | ||
|
||
dimensions: { | ||
_isLinkedToArray: 'dimension', | ||
label: { | ||
valType: 'string', | ||
role: 'info', | ||
description: 'The shown name of the dimension.' | ||
}, | ||
tickvals: axesAttrs.tickvals, | ||
ticktext: axesAttrs.ticktext, | ||
tickformat: { | ||
valType: 'string', | ||
dflt: '3s', | ||
role: 'style', | ||
description: [ | ||
'Sets the tick label formatting rule using d3 formatting mini-language', | ||
'which is similar to those of Python. See', | ||
'https://github.com/d3/d3-format/blob/master/README.md#locale_format' | ||
].join(' ') | ||
}, | ||
visible: { | ||
valType: 'boolean', | ||
dflt: true, | ||
role: 'info', | ||
description: 'Shows the dimension when set to `true` (the default). Hides the dimension for `false`.' | ||
}, | ||
range: { | ||
valType: 'info_array', | ||
role: 'info', | ||
items: [ | ||
{valType: 'number'}, | ||
{valType: 'number'} | ||
], | ||
description: [ | ||
'The domain range that represents the full, shown axis extent. Defaults to the `values` extent.', | ||
'Must be an array of `[fromValue, toValue]` with finite numbers as elements.' | ||
].join(' ') | ||
}, | ||
constraintrange: { | ||
valType: 'info_array', | ||
role: 'info', | ||
items: [ | ||
{valType: 'number'}, | ||
{valType: 'number'} | ||
], | ||
description: [ | ||
'The domain range to which the filter on the dimension is constrained. Must be an array', | ||
'of `[fromValue, toValue]` with finite numbers as elements.' | ||
].join(' ') | ||
}, | ||
values: { | ||
valType: 'data_array', | ||
role: 'info', | ||
dflt: [], | ||
description: [ | ||
'Dimension values. `values[n]` represents the value of the `n`th point in the dataset,', | ||
'therefore the `values` vector for all dimensions must be the same (longer vectors', | ||
'will be truncated). Each value must be a finite number.' | ||
].join(' ') | ||
}, | ||
description: 'The dimensions (variables) of the parallel coordinates chart. 2..60 dimensions are supported.' | ||
}, | ||
|
||
line: extendFlat({}, | ||
|
||
// the default autocolorscale isn't quite usable for parcoords due to context ambiguity around 0 (grey, off-white) | ||
// autocolorscale therefore defaults to false too, to avoid being overridden by the blue-white-red autocolor palette | ||
extendDeep( | ||
{}, | ||
colorAttributes('line'), | ||
{ | ||
colorscale: extendDeep( | ||
{}, | ||
colorAttributes('line').colorscale, | ||
{dflt: colorscales.Viridis} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Very strong choice! We should probably make |
||
), | ||
autocolorscale: extendDeep( | ||
{}, | ||
colorAttributes('line').autocolorscale, | ||
{ | ||
dflt: false, | ||
description: [ | ||
'Has an effect only if line.color` is set to a numerical array.', | ||
'Determines whether the colorscale is a default palette (`autocolorscale: true`)', | ||
'or the palette determined by `line.colorscale`.', | ||
'In case `colorscale` is unspecified or `autocolorscale` is true, the default ', | ||
'palette will be chosen according to whether numbers in the `color` array are', | ||
'all positive, all negative or mixed.', | ||
'The default value is false, so that `parcoords` colorscale can default to `Viridis`.' | ||
].join(' ') | ||
} | ||
) | ||
|
||
} | ||
), | ||
|
||
{ | ||
showscale: { | ||
valType: 'boolean', | ||
role: 'info', | ||
dflt: false, | ||
description: [ | ||
'Has an effect only if `line.color` is set to a numerical array.', | ||
'Determines whether or not a colorbar is displayed.' | ||
].join(' ') | ||
}, | ||
colorbar: colorbarAttrs | ||
} | ||
) | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/** | ||
* Copyright 2012-2017, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
var d3 = require('d3'); | ||
var Plots = require('../../plots/plots'); | ||
var parcoordsPlot = require('./plot'); | ||
var xmlnsNamespaces = require('../../constants/xmlns_namespaces'); | ||
var c = require('./constants'); | ||
|
||
exports.name = 'parcoords'; | ||
|
||
exports.attr = 'type'; | ||
|
||
exports.plot = function(gd) { | ||
var calcData = Plots.getSubplotCalcData(gd.calcdata, 'parcoords', 'parcoords'); | ||
if(calcData.length) parcoordsPlot(gd, calcData); | ||
}; | ||
|
||
exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout) { | ||
var hadParcoords = (oldFullLayout._has && oldFullLayout._has('parcoords')); | ||
var hasParcoords = (newFullLayout._has && newFullLayout._has('parcoords')); | ||
|
||
if(hadParcoords && !hasParcoords) { | ||
oldFullLayout._paperdiv.selectAll('.parcoords-line-layers').remove(); | ||
oldFullLayout._paperdiv.selectAll('.parcoords-line-layers').remove(); | ||
oldFullLayout._paperdiv.selectAll('.parcoords').remove(); | ||
oldFullLayout._paperdiv.selectAll('.parcoords').remove(); | ||
oldFullLayout._glimages.selectAll('*').remove(); | ||
} | ||
}; | ||
|
||
exports.toSVG = function(gd) { | ||
|
||
var imageRoot = gd._fullLayout._glimages; | ||
var root = d3.selectAll('.svg-container'); | ||
var canvases = root.filter(function(d, i) {return i === root.size() - 1;}) | ||
.selectAll('.parcoords-lines.context, .parcoords-lines.focus'); | ||
|
||
function canvasToImage(d) { | ||
var canvas = this; | ||
var imageData = canvas.toDataURL('image/png'); | ||
var image = imageRoot.append('svg:image'); | ||
var size = gd._fullLayout._size; | ||
var domain = gd._fullData[d.model.key].domain; | ||
|
||
image.attr({ | ||
xmlns: xmlnsNamespaces.svg, | ||
'xlink:href': imageData, | ||
x: size.l + size.w * domain.x[0] - c.overdrag, | ||
y: size.t + size.h * (1 - domain.y[1]), | ||
width: (domain.x[1] - domain.x[0]) * size.w + 2 * c.overdrag, | ||
height: (domain.y[1] - domain.y[0]) * size.h, | ||
preserveAspectRatio: 'none' | ||
}); | ||
} | ||
|
||
imageRoot.selectAll('*').remove(); | ||
canvases.each(canvasToImage); | ||
|
||
// Chrome / Safari bug workaround - browser apparently loses connection to the defined pattern | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks very much for the comment 🎉 |
||
// Without the workaround, these browsers 'lose' the filter brush styling (color etc.) after a snapshot | ||
// on a subsequent interaction. | ||
// Firefox works fine without this workaround | ||
window.setTimeout(function() { | ||
d3.selectAll('#filterBarPattern') | ||
.attr('id', 'filterBarPattern'); | ||
}, 60); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/** | ||
* Copyright 2012-2017, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
var hasColorscale = require('../../components/colorscale/has_colorscale'); | ||
var calcColorscale = require('../../components/colorscale/calc'); | ||
var Lib = require('../../lib'); | ||
|
||
|
||
module.exports = function calc(gd, trace) { | ||
var cs = !!trace.line.colorscale && Lib.isArray(trace.line.color); | ||
var color = cs ? trace.line.color : Array.apply(0, Array(trace.dimensions.reduce(function(p, n) {return Math.max(p, n.values.length);}, 0))).map(function() {return 0.5;}); | ||
var cscale = cs ? trace.line.colorscale : [[0, trace.line.color], [1, trace.line.color]]; | ||
|
||
trace.line.color = color; | ||
trace.line.colorscale = cscale; | ||
|
||
if(hasColorscale(trace, 'line')) { | ||
calcColorscale(trace, trace.line.color, 'line', 'c'); | ||
} | ||
|
||
return [{}]; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/** | ||
* Copyright 2012-2017, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
'use strict'; | ||
|
||
var isNumeric = require('fast-isnumeric'); | ||
|
||
var Lib = require('../../lib'); | ||
var Plots = require('../../plots/plots'); | ||
var Colorscale = require('../../components/colorscale'); | ||
var drawColorbar = require('../../components/colorbar/draw'); | ||
|
||
|
||
module.exports = function colorbar(gd, cd) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to self: generalise this and make some reusable routine for all trace types that support colorbars. |
||
var trace = cd[0].trace, | ||
line = trace.line, | ||
cbId = 'cb' + trace.uid; | ||
|
||
gd._fullLayout._infolayer.selectAll('.' + cbId).remove(); | ||
|
||
if((line === undefined) || !line.showscale) { | ||
Plots.autoMargin(gd, cbId); | ||
return; | ||
} | ||
|
||
var vals = line.color, | ||
cmin = line.cmin, | ||
cmax = line.cmax; | ||
|
||
if(!isNumeric(cmin)) cmin = Lib.aggNums(Math.min, null, vals); | ||
if(!isNumeric(cmax)) cmax = Lib.aggNums(Math.max, null, vals); | ||
|
||
var cb = cd[0].t.cb = drawColorbar(gd, cbId); | ||
var sclFunc = Colorscale.makeColorScaleFunc( | ||
Colorscale.extractScale( | ||
line.colorscale, | ||
cmin, | ||
cmax | ||
), | ||
{ noNumericCheck: true } | ||
); | ||
|
||
cb.fillcolor(sclFunc) | ||
.filllevels({start: cmin, end: cmax, size: (cmax - cmin) / 254}) | ||
.options(line.colorbar)(); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did we settle the
dimensions
vsdims
debate?I got to like
dimensions
better (as e.g. we don't abbreviateannotations
), but we should make sure @cldougl @chriddyp @alexcjohnson agree.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 I definitely prefer
dimensions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, feedback was unanimous, no code change then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great.
dimensions
✅