joyplots working

This commit is contained in:
Colin Megill
2017-09-06 22:19:55 -07:00
parent 129ffa1ec6
commit 0e36aaf830
20 changed files with 680 additions and 146 deletions
+116
View File
@@ -0,0 +1,116 @@
import styles from "./joy.css";
/*
via https://bl.ocks.org/armollica/3b5f83836c1de5cca7b1d35409a013e3
*/
var margin = { top: 30, right: 10, bottom: 30, left: 100 },
width = 400 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
// Percent two area charts can overlap
var overlap = 0.4;
var formatTime = d3.timeFormat('%I %p');
var x = function(d) { return d.time; },
xScale = d3.scaleTime().range([0, width]),
xValue = function(d) { return xScale(x(d)); },
xAxis = d3.axisBottom(xScale).tickFormat(formatTime);
var y = function(d) { return d.value; },
yScale = d3.scaleLinear(),
yValue = function(d) { return yScale(y(d)); };
var activity = function(d) { return d.key; },
activityScale = d3.scaleBand().range([0, height]),
activityValue = function(d) { return activityScale(activity(d)); },
activityAxis = d3.axisLeft(activityScale);
var area = d3.area()
.x(xValue)
.y1(yValue);
var line = area.lineY1();
function parseTime(offset) {
var date = new Date(2017, 0, 1); // chose an arbitrary day
return d3.timeMinute.offset(date, offset);
}
function row(d) {
return {
activity: d.activity,
time: parseTime(d.time),
value: +d.p_smooth
};
}
const drawJoy = (data) => {
console.log('drawJoy: ', data)
var svg = d3.select('#joyplot').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 + ')');
d3.tsv("https://gist.githubusercontent.com/armollica/3b5f83836c1de5cca7b1d35409a013e3/raw/783d1bbc2dd3aabbfcba83ece4a670de6f1ec371/data.tsv", row, function(error, dataFlat) {
// Sort by time
dataFlat.sort(function(a, b) { return a.time - b.time; });
var data = d3.nest()
.key(function(d) { return d.activity; })
.entries(dataFlat);
// Sort activities by peak activity time
function peakTime(d) {
var i = d3.scan(d.values, function(a, b) { return y(b) - y(a); });
return d.values[i].time;
};
data.sort(function(a, b) { return peakTime(b) - peakTime(a); });
console.log('sorted', data)
xScale.domain(d3.extent(dataFlat, x));
activityScale.domain(data.map(function(d) { return d.key; }));
var areaChartHeight = (1 + overlap) * (height / activityScale.domain().length);
yScale
.domain(d3.extent(dataFlat, y))
.range([areaChartHeight, 0]);
area.y0(yScale(0));
var gActivity = svg.append('g').attr('class', "activities")
.selectAll('.activity').data(data)
.enter().append('g')
.attr('class', function(d) { return `${styles.activity} ${styles.activity["--"+d.key]}`; })
.attr('transform', function(d) {
var ty = activityValue(d) - activityScale.bandwidth() + 5;
return 'translate(0,' + ty + ')';
});
gActivity.append('path').attr('class', styles.area)
.datum(function(d) { return d.values; })
.attr('d', area);
gActivity.append('path').attr('class', styles.line)
.datum(function(d) { return d.values; })
.attr('d', line);
svg.append('g').attr('class', `${styles.axis} ${styles["axis--x"]}`)
.attr('transform', 'translate(0,' + height + ')')
.call(xAxis);
svg.append('g').attr('class', `${styles.axis} ${styles["axis--activity"]}`)
.call(activityAxis);
})
}
export default drawJoy;
+42
View File
@@ -0,0 +1,42 @@
svg {
display: block;
/*margin: 0 auto;*/
}
.axis .domain {
display: none;
}
.axis--x text {
fill: #999;
}
.axis--x line {
stroke: #aaa;
}
.axis--activity .tick line {
display: none;
}
.axis--activity text {
font-size: 12px;
fill: #000;
}
/*.axis--activity .tick:nth-child(odd) text {
fill: #222;
}*/
.line {
fill: none;
stroke: #fff;
}
.area {
fill: #448cab;
}
.activity:nth-child(odd) .area {
fill: #5ca3c1;
}
+38
View File
@@ -0,0 +1,38 @@
import React from 'react';
import _ from "lodash";
import styles from "./joy.css";
import drawJoy from "./drawJoy";
import joyParser from "./joyParser";
class Joy extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.data) {
console.log('joyplot data 44', nextProps.data)
drawJoy(joyParser(nextProps.data));
}
}
componentDidMount() {
}
render() {
return (
<div id="joyplot_wrapper" style={{marginTop: 50}}>
<h3> Joy </h3>
<p> Cell expression distribution per gene & if differential expression, Ie., cells for cluster 5, top genes expressed by cluster 8</p>
<div id="joyplot"> </div>
</div>
)
}
};
export default Joy;
+30
View File
@@ -0,0 +1,30 @@
const joyParser = (data, count = 20) => {
const genes = [];
/* setup */
for (let i = 0; i < count; i++) {
const gene = {
key: data.genes[i], /* key values naming: https://bl.ocks.org/armollica/3b5f83836c1de5cca7b1d35409a013e3 */
values: []
}
data.cells.forEach((cell) => {
gene.values.push({
value: cell["e"][i]
})
})
genes.push(gene)
}
return genes;
}
export default joyParser;