drawing graph

This commit is contained in:
Colin Megill
2017-09-08 01:08:01 -07:00
parent 0e36aaf830
commit b6be4947eb
6 changed files with 155 additions and 201 deletions
@@ -1,4 +1,5 @@
import styles from './parallelCoordinates.css'; import styles from './parallelCoordinates.css';
import renderQueue from "./renderQueue";
import { import {
margin, margin,
width, width,
@@ -17,89 +18,6 @@ Canvas Parallel coordinates with svg brushing via /* via https://bl.ocks.org/syn
****************************************** ******************************************
******************************************/ ******************************************/
/*****************************************
******************************************
Render Queue via http://bl.ocks.org/syntagmatic/raw/3341641/render-queue.js
******************************************
******************************************/
const renderQueue = (function(callback1234) {
var _queue = [], // data to be rendered
_rate = 1000, // number of calls per frame
_invalidate = function() {}, // invalidate last render queue
_clear = function() {}; // clearing function
var rq = function(data) {
if (data) rq.data(data);
_invalidate();
_clear();
rq.render();
};
rq.render = function() {
var valid = true;
_invalidate = rq.invalidate = function() {
valid = false;
};
function doFrame() {
if (!valid) return true;
var chunk = _queue.splice(0,_rate);
chunk.map(callback1234);
timer_frame(doFrame);
}
doFrame();
};
rq.data = function(data) {
_invalidate();
_queue = data.slice(0); // creates a copy of the data
return rq;
};
rq.add = function(data) {
_queue = _queue.concat(data);
};
rq.rate = function(value) {
if (!arguments.length) return _rate;
_rate = value;
return rq;
};
rq.remaining = function() {
return _queue.length;
};
// clear the canvas
rq.clear = function(func) {
if (!arguments.length) {
_clear();
return rq;
}
_clear = func;
return rq;
};
rq.invalidate = _invalidate;
var timer_frame = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { setTimeout(callback, 17); };
return rq;
});
/*****************************************
******************************************
MAIN: drawParallelCoordinates
******************************************
******************************************/
const drawParallelCoordinates = (data) => { const drawParallelCoordinates = (data) => {
const d3_functor = (v) => { const d3_functor = (v) => {
+78
View File
@@ -0,0 +1,78 @@
/*****************************************
******************************************
Render Queue via http://bl.ocks.org/syntagmatic/raw/3341641/render-queue.js
******************************************
******************************************/
const renderQueue = (function(callback1234) {
var _queue = [], // data to be rendered
_rate = 1000, // number of calls per frame
_invalidate = function() {}, // invalidate last render queue
_clear = function() {}; // clearing function
var rq = function(data) {
if (data) rq.data(data);
_invalidate();
_clear();
rq.render();
};
rq.render = function() {
var valid = true;
_invalidate = rq.invalidate = function() {
valid = false;
};
function doFrame() {
if (!valid) return true;
var chunk = _queue.splice(0,_rate);
chunk.map(callback1234);
timer_frame(doFrame);
}
doFrame();
};
rq.data = function(data) {
_invalidate();
_queue = data.slice(0); // creates a copy of the data
return rq;
};
rq.add = function(data) {
_queue = _queue.concat(data);
};
rq.rate = function(value) {
if (!arguments.length) return _rate;
_rate = value;
return rq;
};
rq.remaining = function() {
return _queue.length;
};
// clear the canvas
rq.clear = function(func) {
if (!arguments.length) {
_clear();
return rq;
}
_clear = func;
return rq;
};
rq.invalidate = _invalidate;
var timer_frame = window.requestAnimationFrame
|| window.webkitRequestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.oRequestAnimationFrame
|| window.msRequestAnimationFrame
|| function(callback) { setTimeout(callback, 17); };
return rq;
});
export default renderQueue;
+45 -96
View File
@@ -1,118 +1,67 @@
var margin = {top: 20, right: 10, bottom: 30, left: 40}, import styles from "./graph.css";
import renderQueue from "../continuous/renderQueue";
const margin = {top: 20, right: 10, bottom: 30, left: 40},
width = 960 - margin.left - margin.right, width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom; height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg") const x = d3.scaleLinear()
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + " " + margin.top + ")");
var factory = d3.geom.quadtree()
.extent([
[0, 0],
[width, height]
]);
var x = d3.scale.linear()
.range([0, width]); .range([0, width]);
var y = d3.scale.linear() const y = d3.scaleLinear()
.range([height, 0]); .range([height, 0]);
var xAxis = d3.svg.axis() /******************************************
.scale(x) *******************************************
.orient("bottom"); Main
*******************************************
******************************************/
var yAxis = d3.svg.axis() const drawGraph = (data) => {
.scale(y)
.orient("left");
var xg = svg.append("g") var svg = d3.select("#graphAttachPoint").append("svg")
.attr("class", "x axis") .attr("width", width + margin.left + margin.right)
.attr("transform", "translate(0," + height + ")"); .attr("height", height + margin.top + margin.bottom)
.attr("class", `${styles.graphSVG}`)
.append("g")
.attr("transform", "translate(" + margin.left + " " + margin.top + ")");
var yg = svg.append("g") var chartArea = d3.select("#graphAttachPoint").append("div")
.attr("class", "y axis"); .style("left", margin.left + "px")
.style("top", margin.top + "px");
var chartArea = d3.select("body").append("div") var canvas = chartArea.append("canvas")
.style("left", margin.left + "px") .attr("width", width)
.style("top", margin.top + "px"); .attr("height", height)
.attr("class", `${styles.graphCanvas}`);
var canvas = chartArea.append("canvas") var context = canvas.node().getContext("2d");
.attr("width", width)
.attr("height", height);
var context = canvas.node().getContext("2d"); context.fillStyle = "rgba(0,0,0,.5)";
context.fillStyle = "#f0f"; const draw = () => {
// Layer on top of canvas, example of selection details // Update canvas
var highlight = chartArea.append("svg") context.clearRect(0, 0, width, height);
.attr("width", width)
.attr("height", height)
.append("circle")
.attr("r", 7)
.classed("hidden", true);
redraw(); data.forEach((p, i) => {
function redraw() { context.beginPath();
/* context.arc(x,y,r,sAngle,eAngle,counterclockwise); */
context.arc(
x(p[1]), /* x */
y(p[2]), /* y */
2, /* r */
0, /* sAngle */
2 * Math.PI /* eAngle */
);
context.fill();
// Randomize the scale });
var scale = 1 + Math.floor(Math.random() * 10); }
// Redraw axes draw();
x.domain([0, scale]);
y.domain([0, scale]);
xg.call(xAxis);
yg.call(yAxis);
var points = randomPoints(scale);
var tree = factory(points);
// Update canvas
context.clearRect(0, 0, width, height);
points.forEach(function(p,i){
context.beginPath();
context.arc(x(p[0]), y(p[1]), 5, 0, 2 * Math.PI);
context.fill();
});
canvas.on("mousemove",function(){
var mouse = d3.mouse(this),
closest = tree.find([x.invert(mouse[0]), y.invert(mouse[1])]);
highlight.attr("cx", x(closest[0]))
.attr("cy", y(closest[1]));
});
canvas.on("mouseover",function(){
highlight.classed("hidden", false);
});
canvas.on("mouseout",function(){
highlight.classed("hidden", true);
});
} }
function randomPoints(scale) { export default drawGraph;
// Get points
return d3.range(1000).map(function(d){
return [
Math.random() * scale,
Math.random() * scale
];
});
}
+9 -6
View File
@@ -1,15 +1,18 @@
path, .graphCanvas path {
line {
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }
div, #graphWrapper {
svg, position: relative;
canvas { }
#graphAttachPoint,
.graphSVG,
.graphCanvas {
position: absolute; position: absolute;
} }
svg { #graphSVG {
pointer-events: none; pointer-events: none;
} }
+10 -13
View File
@@ -1,34 +1,31 @@
import React from 'react'; import React from 'react';
import _ from "lodash"; import _ from "lodash";
// import styles from "./joy.css"; import styles from "./graph.css";
// import drawGraph from "./drawGraph"; import drawGraph from "./drawGraph";
// import joyParser from "./joyParser";
class Graph extends React.Component { class Graph extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
drawn: false,
}; };
} }
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
if (nextProps.data) { /* maybe should do a check here to confirm ref exists and pass it? */
console.log('graph data 55', nextProps.data) if (nextProps.data && !this.state.drawn) {
// drawGraph(graphParser(nextProps.data)); console.log('About to draw graph. Data:', nextProps.data)
drawGraph(nextProps.data.data)
this.setState({drawn: true});
} }
} }
componentDidMount() {
}
render() { render() {
return ( return (
<div id="joyplot_wrapper" style={{marginTop: 50}}> <div id="graphWrapper">
<h3> Graph </h3> <h3> Graph </h3>
<div id="joyplot"> </div> <div id="graphAttachPoint"> </div>
</div> </div>
) )
} }
+12 -3
View File
@@ -19,7 +19,7 @@ class Home extends React.Component {
graph: null, graph: null,
}; };
} }
componentWillMount() { componentDidMount() {
// d3.csv("http://ec2-34-234-75-156.compute-1.amazonaws.com/api/v0.1/metadata", (d) => { // d3.csv("http://ec2-34-234-75-156.compute-1.amazonaws.com/api/v0.1/metadata", (d) => {
// console.log("from ec2",d) // console.log("from ec2",d)
// }) // })
@@ -51,13 +51,22 @@ class Home extends React.Component {
<Container> <Container>
<Helmet title="cellxgene" /> <Helmet title="cellxgene" />
<h1><Link to="/page2">cellxgene</Link></h1> <h1><Link to="/page2">cellxgene</Link></h1>
<button
className={buttonStyles.primaryButton}>
Showing a cluster informed downsampling of 10,000 cells. Refresh.
</button>
<h3 style={{marginTop: 50}}> Gene selection criteria </h3> <h3 style={{marginTop: 50}}> Gene selection criteria </h3>
<Joy data={this.state.heatmap && this.state.heatmap.data}/> {false ? <Joy data={this.state.heatmap && this.state.heatmap.data}/> : ""}
<Categorical/> <Categorical/>
<Continuous/> <Continuous/>
<h3 style={{marginTop: 50}}> T-SNE plot </h3> <h3 style={{marginTop: 50}}> T-SNE plot </h3>
<button onClick={() => { this.setState({showClustersPlaceholderImage: true}) }} style={{marginBottom: 20}} className={buttonStyles.primaryButton}>Compute clustering using [n] cells in current metadata selection</button> <button
onClick={() => { this.setState({showClustersPlaceholderImage: true}) }}
style={{marginBottom: 20}}
className={buttonStyles.primaryButton}>
Compute clustering using [n] cells in current metadata selection
</button>
<Graph data={this.state.graph}/> <Graph data={this.state.graph}/>
{this.state.showClustersPlaceholderImage ? <img width={750} src="https://s10.postimg.org/s6z3zbcvt/tsne.png"></img> : null} {this.state.showClustersPlaceholderImage ? <img width={750} src="https://s10.postimg.org/s6z3zbcvt/tsne.png"></img> : null}
</Container> </Container>