forked from apache/superset
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[SIP-5] Refactor parallel coordinates (apache#5761)
* Extract slice and formData * organize imports
- Loading branch information
1 parent
bebbdb8
commit dafe0b9
Showing
1 changed file
with
101 additions
and
60 deletions.
There are no files selected for viewing
161 changes: 101 additions & 60 deletions
161
superset/assets/src/visualizations/parallel_coordinates.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,130 @@ | ||
import d3 from 'd3'; | ||
import PropTypes from 'prop-types'; | ||
import { colorScalerFactory } from '../modules/colors'; | ||
import parcoords from '../../vendor/parallel_coordinates/d3.parcoords'; | ||
import divgrid from '../../vendor/parallel_coordinates/divgrid'; | ||
import '../../vendor/parallel_coordinates/d3.parcoords.css'; | ||
import './parallel_coordinates.css'; | ||
import { colorScalerFactory } from '../modules/colors'; | ||
|
||
d3.parcoords = require('../../vendor/parallel_coordinates/d3.parcoords.js'); | ||
d3.divgrid = require('../../vendor/parallel_coordinates/divgrid.js'); | ||
const propTypes = { | ||
// Standard tabular data [{ fieldName1: value1, fieldName2: value2 }] | ||
data: PropTypes.arrayOf(PropTypes.object), | ||
width: PropTypes.number, | ||
height: PropTypes.number, | ||
colorMetric: PropTypes.string, | ||
includeSeries: PropTypes.bool, | ||
linearColorScheme: PropTypes.string, | ||
metrics: PropTypes.arrayOf(PropTypes.string), | ||
series: PropTypes.string, | ||
showDatatable: PropTypes.bool, | ||
}; | ||
|
||
const $ = require('jquery'); | ||
function ParallelCoordinates(element, props) { | ||
PropTypes.checkPropTypes(propTypes, props, 'prop', 'ParallelCoordinates'); | ||
|
||
function parallelCoordVis(slice, payload) { | ||
$('#code').attr('rows', '15'); | ||
const fd = slice.formData; | ||
const data = payload.data; | ||
const { | ||
data, | ||
width, | ||
height, | ||
colorMetric, | ||
includeSeries, | ||
linearColorScheme, | ||
metrics, | ||
series, | ||
showDatatable, | ||
} = props; | ||
|
||
const metrics = fd.metrics.map(m => m.label || m); | ||
|
||
let cols = metrics; | ||
if (fd.include_series) { | ||
cols = [fd.series].concat(metrics); | ||
} | ||
const cols = includeSeries ? [series].concat(metrics) : metrics; | ||
|
||
const ttypes = {}; | ||
ttypes[fd.series] = 'string'; | ||
metrics.forEach(function (v) { | ||
ttypes[v] = 'number'; | ||
}); | ||
ttypes[series] = 'string'; | ||
metrics.forEach((v) => { ttypes[v] = 'number'; }); | ||
|
||
const secondaryMetric = fd.secondary_metric ? fd.secondary_metric.label : fd.secondary_metric; | ||
const colorScaler = fd.secondary_metric ? | ||
colorScalerFactory(fd.linear_color_scheme, data, d => d[secondaryMetric]) : | ||
() => 'grey'; | ||
const color = d => colorScaler(d[secondaryMetric]); | ||
const container = d3.select(slice.selector); | ||
const colorScaler = colorMetric | ||
? colorScalerFactory(linearColorScheme, data, d => d[colorMetric]) | ||
: () => 'grey'; | ||
const color = d => colorScaler(d[colorMetric]); | ||
const container = d3.select(element); | ||
container.selectAll('*').remove(); | ||
const effHeight = fd.show_datatable ? (slice.height() / 2) : slice.height(); | ||
const effHeight = showDatatable ? (height / 2) : height; | ||
|
||
container.append('div') | ||
.attr('id', 'parcoords_' + slice.container_id) | ||
.style('height', effHeight + 'px') | ||
.classed('parcoords', true); | ||
const div = container.append('div') | ||
.style('height', effHeight + 'px') | ||
.classed('parcoords', true); | ||
|
||
const parcoords = d3.parcoords()('#parcoords_' + slice.container_id) | ||
.width(slice.width()) | ||
.color(color) | ||
.alpha(0.5) | ||
.composite('darken') | ||
.height(effHeight) | ||
.data(data) | ||
.dimensions(cols) | ||
.types(ttypes) | ||
.render() | ||
.createAxes() | ||
.shadows() | ||
.reorderable() | ||
.brushMode('1D-axes'); | ||
const chart = parcoords()(div.node()) | ||
.width(width) | ||
.color(color) | ||
.alpha(0.5) | ||
.composite('darken') | ||
.height(effHeight) | ||
.data(data) | ||
.dimensions(cols) | ||
.types(ttypes) | ||
.render() | ||
.createAxes() | ||
.shadows() | ||
.reorderable() | ||
.brushMode('1D-axes'); | ||
|
||
if (fd.show_datatable) { | ||
if (showDatatable) { | ||
// create data table, row hover highlighting | ||
const grid = d3.divgrid(); | ||
const grid = divgrid(); | ||
container.append('div') | ||
.style('height', effHeight + 'px') | ||
.datum(data) | ||
.call(grid) | ||
.classed('parcoords grid', true) | ||
.selectAll('.row') | ||
.on({ | ||
mouseover(d) { | ||
parcoords.highlight([d]); | ||
}, | ||
mouseout: parcoords.unhighlight, | ||
}); | ||
.style('height', effHeight + 'px') | ||
.datum(data) | ||
.call(grid) | ||
.classed('parcoords grid', true) | ||
.selectAll('.row') | ||
.on({ | ||
mouseover(d) { | ||
chart.highlight([d]); | ||
}, | ||
mouseout: chart.unhighlight, | ||
}); | ||
// update data table on brush event | ||
parcoords.on('brush', function (d) { | ||
chart.on('brush', function (d) { | ||
d3.select('.grid') | ||
.datum(d) | ||
.call(grid) | ||
.selectAll('.row') | ||
.on({ | ||
mouseover(dd) { | ||
parcoords.highlight([dd]); | ||
chart.highlight([dd]); | ||
}, | ||
mouseout: parcoords.unhighlight, | ||
mouseout: chart.unhighlight, | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = parallelCoordVis; | ||
ParallelCoordinates.propTypes = propTypes; | ||
|
||
function adaptor(slice, payload) { | ||
const { selector, formData } = slice; | ||
const { | ||
include_series: includeSeries, | ||
linear_color_scheme: linearColorScheme, | ||
metrics, | ||
secondary_metric: secondaryMetric, | ||
series, | ||
show_datatable: showDatatable, | ||
} = formData; | ||
const element = document.querySelector(selector); | ||
|
||
return ParallelCoordinates(element, { | ||
data: payload.data, | ||
width: slice.width(), | ||
height: slice.height(), | ||
includeSeries, | ||
linearColorScheme, | ||
metrics: metrics.map(m => m.label || m), | ||
colorMetric: secondaryMetric && secondaryMetric.label | ||
? secondaryMetric.label | ||
: secondaryMetric, | ||
series, | ||
showDatatable, | ||
}); | ||
} | ||
|
||
export default adaptor; |