mirror of
https://github.com/chanzuckerberg/cellxgene.git
synced 2026-09-25 22:28:11 +08:00
Prettier
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// jshint esversion: 6
|
||||
/* rc slider https://www.npmjs.com/package/rc-slider */
|
||||
|
||||
import React from "react";
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import styles from './parallelCoordinates.css';
|
||||
import {
|
||||
yAxis,
|
||||
brushstart,
|
||||
} from "./util";
|
||||
|
||||
// jshint esversion: 6
|
||||
import styles from "./parallelCoordinates.css";
|
||||
import { yAxis, brushstart } from "./util";
|
||||
|
||||
const drawAxes = (
|
||||
svg,
|
||||
@@ -13,19 +10,19 @@ const drawAxes = (
|
||||
height,
|
||||
width,
|
||||
handleBrushAction,
|
||||
handleColorAction,
|
||||
handleColorAction
|
||||
) => {
|
||||
|
||||
/*****************************************
|
||||
******************************************
|
||||
Handles a brush event, toggling the display of foreground lines.
|
||||
******************************************
|
||||
******************************************/
|
||||
|
||||
function brush () {
|
||||
function brush() {
|
||||
var actives = [];
|
||||
svg.selectAll(".parcoords_axis .parcoords_brush")
|
||||
.filter(function (d) {
|
||||
svg
|
||||
.selectAll(".parcoords_axis .parcoords_brush")
|
||||
.filter(function(d) {
|
||||
return d3.brushSelection(this);
|
||||
})
|
||||
.each(function(d) {
|
||||
@@ -35,46 +32,57 @@ const drawAxes = (
|
||||
});
|
||||
});
|
||||
/* fire action, with selected dimensions & their values */
|
||||
handleBrushAction(actives)
|
||||
handleBrushAction(actives);
|
||||
}
|
||||
|
||||
var axes = svg.selectAll(".parcoords_axis")
|
||||
.data(dimensions)
|
||||
.enter().append("g")
|
||||
.attr("class", `${styles.axis} parcoords_axis`)
|
||||
.attr("transform", (d,i) => { return "translate(" + xscale(i) + ")"; });
|
||||
var axes = svg
|
||||
.selectAll(".parcoords_axis")
|
||||
.data(dimensions)
|
||||
.enter()
|
||||
.append("g")
|
||||
.attr("class", `${styles.axis} parcoords_axis`)
|
||||
.attr("transform", (d, i) => {
|
||||
return "translate(" + xscale(i) + ")";
|
||||
});
|
||||
|
||||
axes.append("g")
|
||||
.each(function(d) {
|
||||
var renderAxis = "axis" in d
|
||||
? d.axis.scale(d.scale) // custom axis
|
||||
: yAxis.scale(d.scale); // default axis
|
||||
d3.select(this).call(renderAxis);
|
||||
})
|
||||
axes
|
||||
.append("g")
|
||||
.each(function(d) {
|
||||
var renderAxis =
|
||||
"axis" in d
|
||||
? d.axis.scale(d.scale) // custom axis
|
||||
: yAxis.scale(d.scale); // default axis
|
||||
d3.select(this).call(renderAxis);
|
||||
})
|
||||
.append("text")
|
||||
.on("click", (d) => { handleColorAction(d.key) })
|
||||
.attr("class", styles.title)
|
||||
.attr("text-anchor", "start")
|
||||
.text(function(d) { return "description" in d ? d.description + " 🖌️" : d.key + " 🖌️"; });
|
||||
.on("click", d => {
|
||||
handleColorAction(d.key);
|
||||
})
|
||||
.attr("class", styles.title)
|
||||
.attr("text-anchor", "start")
|
||||
.text(function(d) {
|
||||
return "description" in d ? d.description + " 🖌️" : d.key + " 🖌️";
|
||||
});
|
||||
|
||||
// Add and store a brush for each axis.
|
||||
axes.append("g")
|
||||
.attr("class", `${styles.brush} parcoords_brush`)
|
||||
.each(function(d) {
|
||||
d3.select(this).call(
|
||||
d.brush = d3.brushY()
|
||||
.extent([[-10,0], [10, height]])
|
||||
.on("start", brushstart)
|
||||
.on("brush", brush)
|
||||
.on("end", brush)
|
||||
)
|
||||
})
|
||||
axes
|
||||
.append("g")
|
||||
.attr("class", `${styles.brush} parcoords_brush`)
|
||||
.each(function(d) {
|
||||
d3.select(this).call(
|
||||
(d.brush = d3
|
||||
.brushY()
|
||||
.extent([[-10, 0], [10, height]])
|
||||
.on("start", brushstart)
|
||||
.on("brush", brush)
|
||||
.on("end", brush))
|
||||
);
|
||||
})
|
||||
.selectAll("rect")
|
||||
.attr("x", -8)
|
||||
.attr("width", 16);
|
||||
.attr("x", -8)
|
||||
.attr("width", 16);
|
||||
|
||||
return axes;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
export default drawAxes;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// jshint esversion: 6
|
||||
import _ from "lodash";
|
||||
import {
|
||||
project
|
||||
} from "./util";
|
||||
import { project } from "./util";
|
||||
|
||||
import renderQueue from "../../util/renderQueue";
|
||||
|
||||
@@ -16,16 +15,15 @@ const drawLinesCanvas = (
|
||||
dimensions,
|
||||
xscale,
|
||||
colorAccessor,
|
||||
colorScale,
|
||||
colorScale
|
||||
) => {
|
||||
return (d) => {
|
||||
|
||||
ctx.globalAlpha = .1;
|
||||
return d => {
|
||||
ctx.globalAlpha = 0.1;
|
||||
|
||||
if (d["__selected__"]) {
|
||||
ctx.strokeStyle = d["__color__"];
|
||||
} else {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.beginPath();
|
||||
@@ -36,31 +34,31 @@ const drawLinesCanvas = (
|
||||
// this bit renders horizontal lines on the previous/next
|
||||
// dimensions, so that sandwiched null values are visible
|
||||
if (i > 0) {
|
||||
var prev = coords[i-1];
|
||||
var prev = coords[i - 1];
|
||||
if (prev !== null) {
|
||||
ctx.moveTo(prev[0],prev[1]);
|
||||
ctx.lineTo(prev[0]+6,prev[1]);
|
||||
ctx.moveTo(prev[0], prev[1]);
|
||||
ctx.lineTo(prev[0] + 6, prev[1]);
|
||||
}
|
||||
}
|
||||
if (i < coords.length-1) {
|
||||
var next = coords[i+1];
|
||||
if (i < coords.length - 1) {
|
||||
var next = coords[i + 1];
|
||||
if (next !== null) {
|
||||
ctx.moveTo(next[0]-6,next[1]);
|
||||
ctx.moveTo(next[0] - 6, next[1]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
ctx.moveTo(p[0],p[1]);
|
||||
ctx.moveTo(p[0], p[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.lineTo(p[0],p[1]);
|
||||
ctx.lineTo(p[0], p[1]);
|
||||
});
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const drawCellLinesUsingRenderQueue = (
|
||||
metadata,
|
||||
@@ -68,21 +66,14 @@ const drawCellLinesUsingRenderQueue = (
|
||||
xscale,
|
||||
ctx,
|
||||
colorAccessor,
|
||||
colorScale,
|
||||
colorScale
|
||||
) => {
|
||||
|
||||
const _renderLinesWithQueue = renderQueue(
|
||||
drawLinesCanvas(
|
||||
ctx,
|
||||
dimensions,
|
||||
xscale,
|
||||
colorAccessor,
|
||||
colorScale,
|
||||
)
|
||||
drawLinesCanvas(ctx, dimensions, xscale, colorAccessor, colorScale)
|
||||
).rate(50);
|
||||
_renderLinesWithQueue(metadata);
|
||||
return _renderLinesWithQueue;
|
||||
}
|
||||
};
|
||||
|
||||
const drawCellLinesSync = (
|
||||
metadata,
|
||||
@@ -90,17 +81,17 @@ const drawCellLinesSync = (
|
||||
xscale,
|
||||
ctx,
|
||||
colorAccessor,
|
||||
colorScale,
|
||||
colorScale
|
||||
) => {
|
||||
const _draw = drawLinesCanvas(
|
||||
ctx,
|
||||
dimensions,
|
||||
xscale,
|
||||
colorAccessor,
|
||||
colorScale,
|
||||
)
|
||||
_.each(metadata, _draw)
|
||||
}
|
||||
colorScale
|
||||
);
|
||||
_.each(metadata, _draw);
|
||||
};
|
||||
|
||||
export default drawCellLinesUsingRenderQueue;
|
||||
// export default drawCellLinesUsingRenderQueue;
|
||||
|
||||
@@ -3,22 +3,31 @@ https://bl.ocks.org/mbostock/4341954
|
||||
https://bl.ocks.org/mbostock/34f08d5e11952a80609169b7917d4172
|
||||
https://bl.ocks.org/SpaceActuary/2f004899ea1b2bd78d6f1dbb2febf771
|
||||
*/
|
||||
import React from 'react';
|
||||
// jshint esversion: 6
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
@connect((state) => {
|
||||
@connect(state => {
|
||||
const ranges =
|
||||
state.cells.cells && state.cells.cells.data.ranges
|
||||
? state.cells.cells.data.ranges
|
||||
: null;
|
||||
const metadata =
|
||||
state.cells.cells && state.cells.cells.data.metadata
|
||||
? state.cells.cells.data.metadata
|
||||
: null;
|
||||
|
||||
const ranges = state.cells.cells && state.cells.cells.data.ranges ? state.cells.cells.data.ranges : null;
|
||||
const metadata = state.cells.cells && state.cells.cells.data.metadata ? state.cells.cells.data.metadata : null;
|
||||
|
||||
const initializeRanges = state.initialize.data && state.initialize.data.data.ranges ? state.initialize.data.data.ranges : null;
|
||||
const initializeRanges =
|
||||
state.initialize.data && state.initialize.data.data.ranges
|
||||
? state.initialize.data.data.ranges
|
||||
: null;
|
||||
|
||||
return {
|
||||
colorAccessor: state.controls.colorAccessor,
|
||||
colorScale: state.controls.colorScale,
|
||||
currentCellSelection: state.controls.currentCellSelection,
|
||||
}
|
||||
currentCellSelection: state.controls.currentCellSelection
|
||||
};
|
||||
})
|
||||
class HistogramBrush extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -33,15 +42,11 @@ class HistogramBrush extends React.Component {
|
||||
ctx: null,
|
||||
axes: null,
|
||||
dimensions: null,
|
||||
brush: null,
|
||||
brush: null
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
componentDidUpdate() {
|
||||
|
||||
}
|
||||
componentDidMount() {}
|
||||
componentDidUpdate() {}
|
||||
onBrush(selection, x) {
|
||||
return () => {
|
||||
if (d3.event.selection) {
|
||||
@@ -57,81 +62,104 @@ class HistogramBrush extends React.Component {
|
||||
range: null
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
drawHistogram(svgRef) {
|
||||
|
||||
const allValuesForContinuousFieldAsArray = _.map(
|
||||
this.props.currentCellSelection,
|
||||
this.props.metadataField
|
||||
)
|
||||
);
|
||||
|
||||
var x = d3.scaleLinear()
|
||||
.domain(d3.extent(allValuesForContinuousFieldAsArray, (d) => +d))
|
||||
.range([0, this.width])
|
||||
// .range([margin.left, width - margin.right]);
|
||||
var x = d3
|
||||
.scaleLinear()
|
||||
.domain(d3.extent(allValuesForContinuousFieldAsArray, d => +d))
|
||||
.range([0, this.width]);
|
||||
// .range([margin.left, width - margin.right]);
|
||||
|
||||
var y = d3.scaleLinear()
|
||||
.range([this.height - this.marginBottom, 0])
|
||||
// .range([height - margin.bottom, margin.top]);
|
||||
var y = d3.scaleLinear().range([this.height - this.marginBottom, 0]);
|
||||
// .range([height - margin.bottom, margin.top]);
|
||||
|
||||
const bins = d3.histogram()
|
||||
.domain(x.domain())
|
||||
.thresholds(40)(allValuesForContinuousFieldAsArray)
|
||||
const bins = d3
|
||||
.histogram()
|
||||
.domain(x.domain())
|
||||
.thresholds(40)(allValuesForContinuousFieldAsArray);
|
||||
|
||||
d3.select(svgRef)
|
||||
d3
|
||||
.select(svgRef)
|
||||
.insert("g", "*")
|
||||
.attr("fill", "#bbb")
|
||||
.selectAll("rect")
|
||||
.data(bins)
|
||||
.enter().append("rect")
|
||||
.attr("x", function(d) { return x(d.x0) + 1; })
|
||||
.attr("y", function(d) { return y(d.length / allValuesForContinuousFieldAsArray.length); })
|
||||
.attr("width", function(d) { return Math.abs(x(d.x1) - x(d.x0) - 1); })
|
||||
.attr("height", function(d) { return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length); });
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", function(d) {
|
||||
return x(d.x0) + 1;
|
||||
})
|
||||
.attr("y", function(d) {
|
||||
return y(d.length / allValuesForContinuousFieldAsArray.length);
|
||||
})
|
||||
.attr("width", function(d) {
|
||||
return Math.abs(x(d.x1) - x(d.x0) - 1);
|
||||
})
|
||||
.attr("height", function(d) {
|
||||
return y(0) - y(d.length / allValuesForContinuousFieldAsArray.length);
|
||||
});
|
||||
|
||||
if (!this.state.brush && !this.state.axis) {
|
||||
const brush = d3.select(svgRef)
|
||||
.append('g')
|
||||
.attr('class', 'brush')
|
||||
const brush = d3
|
||||
.select(svgRef)
|
||||
.append("g")
|
||||
.attr("class", "brush")
|
||||
.call(
|
||||
d3.brushX()
|
||||
.on('end', this.onBrush(this.props.metadataField, x.invert).bind(this))
|
||||
)
|
||||
d3
|
||||
.brushX()
|
||||
.on(
|
||||
"end",
|
||||
this.onBrush(this.props.metadataField, x.invert).bind(this)
|
||||
)
|
||||
);
|
||||
|
||||
const xAxis = d3.select(svgRef)
|
||||
const xAxis = d3
|
||||
.select(svgRef)
|
||||
.append("g")
|
||||
.attr("class", "axis axis--x")
|
||||
.attr("transform", "translate(0," + (this.height - this.marginBottom) + ")")
|
||||
.call(
|
||||
d3.axisBottom(x)
|
||||
.ticks(5)
|
||||
.attr(
|
||||
"transform",
|
||||
"translate(0," + (this.height - this.marginBottom) + ")"
|
||||
)
|
||||
.call(d3.axisBottom(x).ticks(5))
|
||||
.append("text")
|
||||
.attr("x", 300)
|
||||
.attr("y", -6)
|
||||
.attr("fill", "#000")
|
||||
.attr("text-anchor", "end")
|
||||
.attr("font-weight", "bold")
|
||||
.text(this.props.metadataField)
|
||||
.attr("x", 300)
|
||||
.attr("y", -6)
|
||||
.attr("fill", "#000")
|
||||
.attr("text-anchor", "end")
|
||||
.attr("font-weight", "bold")
|
||||
.text(this.props.metadataField);
|
||||
|
||||
this.setState({brush, xAxis})
|
||||
this.setState({ brush, xAxis });
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div style={{marginTop: 10}} id={"histogram_" + this.props.metadataField}>
|
||||
<svg width={this.width} height={this.height} ref={(svgRef) => { this.drawHistogram(svgRef)}}>
|
||||
<div
|
||||
style={{ marginTop: 10 }}
|
||||
id={"histogram_" + this.props.metadataField}
|
||||
>
|
||||
<svg
|
||||
width={this.width}
|
||||
height={this.height}
|
||||
ref={svgRef => {
|
||||
this.drawHistogram(svgRef);
|
||||
}}
|
||||
>
|
||||
{this.props.ranges.min}
|
||||
{" to "}
|
||||
{this.props.ranges.max}
|
||||
</svg>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default HistogramBrush;
|
||||
export default HistogramBrush;
|
||||
|
||||
@@ -1,29 +1,33 @@
|
||||
// jshint esversion: 6
|
||||
/* rc slider https://www.npmjs.com/package/rc-slider */
|
||||
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import styles from './parallelCoordinates.css';
|
||||
import styles from "./parallelCoordinates.css";
|
||||
import SectionHeader from "../framework/sectionHeader";
|
||||
|
||||
import setupParallelCoordinates from "./setupParallelCoordinates";
|
||||
import drawAxes from "./drawAxes";
|
||||
import drawLinesCanvas from "./drawLinesCanvas";
|
||||
|
||||
import {
|
||||
margin,
|
||||
width,
|
||||
height,
|
||||
createDimensions,
|
||||
} from "./util";
|
||||
import { margin, width, height, createDimensions } from "./util";
|
||||
|
||||
@connect((state) => {
|
||||
@connect(state => {
|
||||
const ranges =
|
||||
state.cells.cells && state.cells.cells.data.ranges
|
||||
? state.cells.cells.data.ranges
|
||||
: null;
|
||||
const metadata =
|
||||
state.cells.cells && state.cells.cells.data.metadata
|
||||
? state.cells.cells.data.metadata
|
||||
: null;
|
||||
|
||||
const ranges = state.cells.cells && state.cells.cells.data.ranges ? state.cells.cells.data.ranges : null;
|
||||
const metadata = state.cells.cells && state.cells.cells.data.metadata ? state.cells.cells.data.metadata : null;
|
||||
|
||||
const initializeRanges = state.initialize.data && state.initialize.data.data.ranges ? state.initialize.data.data.ranges : null;
|
||||
const initializeRanges =
|
||||
state.initialize.data && state.initialize.data.data.ranges
|
||||
? state.initialize.data.data.ranges
|
||||
: null;
|
||||
|
||||
return {
|
||||
ranges,
|
||||
@@ -33,8 +37,8 @@ import {
|
||||
colorScale: state.controls.colorScale,
|
||||
graphBrushSelection: state.controls.graphBrushSelection,
|
||||
currentCellSelection: state.controls.currentCellSelection,
|
||||
axesHaveBeenDrawn: state.controls.axesHaveBeenDrawn,
|
||||
}
|
||||
axesHaveBeenDrawn: state.controls.axesHaveBeenDrawn
|
||||
};
|
||||
})
|
||||
class Parallel extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -43,16 +47,12 @@ class Parallel extends React.Component {
|
||||
svg: null,
|
||||
ctx: null,
|
||||
axes: null,
|
||||
dimensions: null,
|
||||
dimensions: null
|
||||
};
|
||||
}
|
||||
componentDidMount() {
|
||||
const {svg, ctx} = setupParallelCoordinates(
|
||||
width,
|
||||
height,
|
||||
margin
|
||||
);
|
||||
this.setState({svg, ctx})
|
||||
const { svg, ctx } = setupParallelCoordinates(width, height, margin);
|
||||
this.setState({ svg, ctx });
|
||||
}
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.maybeDrawAxes(nextProps);
|
||||
@@ -63,10 +63,10 @@ class Parallel extends React.Component {
|
||||
!this.state.axes &&
|
||||
nextProps.initializeRanges /* axes are created on full range of data */
|
||||
) {
|
||||
|
||||
const dimensions = createDimensions(nextProps.initializeRanges);
|
||||
|
||||
const xscale = d3.scalePoint()
|
||||
const xscale = d3
|
||||
.scalePoint()
|
||||
.domain(d3.range(dimensions.length))
|
||||
.range([0, width]);
|
||||
|
||||
@@ -78,28 +78,27 @@ class Parallel extends React.Component {
|
||||
height,
|
||||
width,
|
||||
this.handleBrushAction.bind(this),
|
||||
this.handleColorAction.bind(this),
|
||||
this.handleColorAction.bind(this)
|
||||
);
|
||||
|
||||
this.setState({
|
||||
axes,
|
||||
xscale,
|
||||
dimensions,
|
||||
})
|
||||
dimensions
|
||||
});
|
||||
|
||||
this.props.dispatch({
|
||||
type: "parallel coordinates axes have been drawn"
|
||||
})
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
maybeDrawLines = _.debounce((nextProps) => { /* https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js */
|
||||
maybeDrawLines = _.debounce(nextProps => {
|
||||
/* https://stackoverflow.com/questions/23123138/perform-debounce-in-react-js */
|
||||
if (
|
||||
nextProps.ranges &&
|
||||
nextProps.currentCellSelection &&
|
||||
nextProps.axesHaveBeenDrawn
|
||||
) {
|
||||
|
||||
if (this.state._drawLinesCanvas) {
|
||||
this.state._drawLinesCanvas.invalidate(); /* this is only necessary if the internals of drawLinesCanvas are using the render queue */
|
||||
}
|
||||
@@ -112,22 +111,22 @@ class Parallel extends React.Component {
|
||||
this.state.xscale,
|
||||
this.state.ctx,
|
||||
nextProps.colorAccessor,
|
||||
nextProps.colorScale,
|
||||
nextProps.colorScale
|
||||
);
|
||||
|
||||
this.setState({
|
||||
_drawLinesCanvas, /* this will only exist if the internals of drawLinesCanvas are using the render queue */
|
||||
})
|
||||
_drawLinesCanvas /* this will only exist if the internals of drawLinesCanvas are using the render queue */
|
||||
});
|
||||
}
|
||||
}, 200)
|
||||
}, 200);
|
||||
|
||||
handleBrushAction (selection) {
|
||||
handleBrushAction(selection) {
|
||||
this.props.dispatch({
|
||||
type: "continuous selection using parallel coords brushing",
|
||||
data: selection
|
||||
})
|
||||
});
|
||||
}
|
||||
handleColorAction (key) {
|
||||
handleColorAction(key) {
|
||||
this.props.dispatch({
|
||||
type: "color by continuous metadata",
|
||||
colorAccessor: key,
|
||||
@@ -136,22 +135,21 @@ class Parallel extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div id="parcoords_wrapper">
|
||||
<div
|
||||
className={styles.parcoords}
|
||||
id="parcoords"
|
||||
style={{
|
||||
width: width + margin.left + margin.right + "px",
|
||||
width: width + margin.left + margin.right + "px",
|
||||
height: height + margin.top + margin.bottom + "px"
|
||||
}}></div>
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default Parallel;
|
||||
|
||||
|
||||
// <SectionHeader text="Continuous Metadata"/>
|
||||
|
||||
@@ -3,22 +3,19 @@
|
||||
Setup SVG & Canvas elements
|
||||
******************************************
|
||||
******************************************/
|
||||
// jshint esversion: 6
|
||||
const setupParallelCoordinates = (width, height, margin) => {
|
||||
var container = d3.select("#parcoords");
|
||||
|
||||
const setupParallelCoordinates = (
|
||||
width,
|
||||
height,
|
||||
margin
|
||||
) => {
|
||||
|
||||
var container = d3.select("#parcoords")
|
||||
|
||||
var svg = container.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
var svg = container
|
||||
.append("svg")
|
||||
.attr("width", width + margin.left + margin.right)
|
||||
.attr("height", height + margin.top + margin.bottom)
|
||||
.append("g")
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
||||
|
||||
var canvas = container.append("canvas")
|
||||
var canvas = container
|
||||
.append("canvas")
|
||||
.attr("width", width * devicePixelRatio)
|
||||
.attr("height", height * devicePixelRatio)
|
||||
.style("width", width + "px")
|
||||
@@ -27,16 +24,15 @@ const setupParallelCoordinates = (
|
||||
.style("margin-left", margin.left + "px");
|
||||
|
||||
var ctx = canvas.node().getContext("2d");
|
||||
ctx.globalCompositeOperation = 'darken';
|
||||
ctx.globalAlpha = 0.15;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.scale(devicePixelRatio, devicePixelRatio);
|
||||
ctx.globalCompositeOperation = "darken";
|
||||
ctx.globalAlpha = 0.15;
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.scale(devicePixelRatio, devicePixelRatio);
|
||||
|
||||
return {
|
||||
svg,
|
||||
ctx,
|
||||
}
|
||||
ctx
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
export default setupParallelCoordinates
|
||||
export default setupParallelCoordinates;
|
||||
|
||||
@@ -1,51 +1,57 @@
|
||||
// jshint esversion: 6
|
||||
import _ from "lodash";
|
||||
|
||||
const paddingRight = 120;
|
||||
const continuousChartWidth = 1200;
|
||||
|
||||
export const margin = {top: 66, right: 110, bottom: 20, left: 60};
|
||||
export const width = continuousChartWidth - margin.left - margin.right - paddingRight;
|
||||
export const margin = { top: 66, right: 110, bottom: 20, left: 60 };
|
||||
export const width =
|
||||
continuousChartWidth - margin.left - margin.right - paddingRight;
|
||||
export const height = 340 - margin.top - margin.bottom;
|
||||
export const innerHeight = height - 2;
|
||||
|
||||
export const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
|
||||
export const createDimensions = (data) => {
|
||||
const newArr = []
|
||||
export const createDimensions = data => {
|
||||
const newArr = [];
|
||||
_.each(data, (value, key) => {
|
||||
if (value.range) {
|
||||
newArr.push({
|
||||
key: key, /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */
|
||||
key: key /* room for confusion: lodash calls this key, it's also the name of the property parallel coords code is looking for */,
|
||||
type: {
|
||||
within: (d, extent, dim) => {
|
||||
return extent[0] <= dim.scale(d) && dim.scale(d) <= extent[1];
|
||||
},
|
||||
}
|
||||
},
|
||||
scale: d3.scaleSqrt().range([innerHeight, 0]).domain([0, value.range.max])
|
||||
})
|
||||
scale: d3
|
||||
.scaleSqrt()
|
||||
.range([innerHeight, 0])
|
||||
.domain([0, value.range.max])
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
return newArr;
|
||||
}
|
||||
};
|
||||
|
||||
export const yAxis = d3.axisLeft();
|
||||
|
||||
export const brushstart = () => {
|
||||
d3.event.sourceEvent.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
export const d3_functor = (v) => {
|
||||
return typeof v === "function" ? v : () => { return v; };
|
||||
export const d3_functor = v => {
|
||||
return typeof v === "function"
|
||||
? v
|
||||
: () => {
|
||||
return v;
|
||||
};
|
||||
};
|
||||
|
||||
export const project = (d, dimensions, xscale) => {
|
||||
return dimensions.map((p,i) => {
|
||||
return dimensions.map((p, i) => {
|
||||
// check if data element has property and contains a value
|
||||
if (
|
||||
!(p.key in d) ||
|
||||
d[p.key] === null
|
||||
) return null;
|
||||
if (!(p.key in d) || d[p.key] === null) return null;
|
||||
|
||||
return [xscale(i),p.scale(d[p.key])];
|
||||
return [xscale(i), p.scale(d[p.key])];
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user