Skip to content

Commit

Permalink
[SIP-5] Refactor parallel coordinates (apache#5761)
Browse files Browse the repository at this point in the history
* Extract slice and formData

* organize imports
  • Loading branch information
kristw authored and williaster committed Sep 5, 2018
1 parent bebbdb8 commit dafe0b9
Showing 1 changed file with 101 additions and 60 deletions.
161 changes: 101 additions & 60 deletions superset/assets/src/visualizations/parallel_coordinates.js
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;

0 comments on commit dafe0b9

Please sign in to comment.