Skip to content

Commit

Permalink
Hacky gene track for Friday demo
Browse files Browse the repository at this point in the history
  • Loading branch information
danvk committed Mar 13, 2015
1 parent 9c96e36 commit 0656f73
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 9 deletions.
18 changes: 17 additions & 1 deletion src/BigBed.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ function generateContigMap(twoBitHeader): {[key:string]: number} {
}));
}

function reverseContigMap(contigMap: {[key:string]: number}): Array<string> {
var ary = [];
_.forEach(contigMap, (index, name) => {
ary[index] = name;
});
return ary;
}

function getContigId(contigMap, contig) {
return contigMap[contig] || contigMap['chr' + contig] || null;
}
Expand Down Expand Up @@ -283,7 +291,15 @@ class BigBed {
var range = Interval.boundingInterval(
blocks.map(n => new Interval(+n.offset, n.offset+n.size)));
return this.remoteFile.getBytes(range.start, range.length())
.then(dataView => extractFeaturesInRange(dataView, range, blocks, contigRange));
.then(dataView => {
var reverseMap = reverseContigMap(contigMap);
var features = extractFeaturesInRange(dataView, range, blocks, contigRange)
features.forEach(f => {
f.contig = reverseMap[f.chrId];
delete f.chrId;
});
return features;
});
});
}
}
Expand Down
56 changes: 56 additions & 0 deletions src/BigBedDataSource.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';

var Events = require('backbone').Events,
_ = require('underscore');


var ContigInterval = require('./ContigInterval');


function createBigBedDataSource(remoteSource: BigBed) {
// (ContigInterval, name) tuples
var features = [];

function addFeature(contigInterval, name) {
for (var i = 0; i < features.length; i++) {
var f = features[i];
if (f[0].isEqual(contigInterval)) return;
}
features.push([contigInterval, name]);
}

function getFeaturesInRange(range) {
if (!range) return [];
var contigInterval = new ContigInterval(range.contig, range.start, range.stop);
return features.filter(x => contigInterval.intersects(x[0]));
}

function fetch(range: GenomeRange) {
return remoteSource.getFeaturesInRange(range.contig, range.start, range.stop)
.then(features => {
features.forEach(f => {
var range = new ContigInterval(f.contig, f.start, f.end);
var info = f.rest.split('\t');
var strand = info[2]; // either + or -
var ensembleId = info[0]; // e.g. ENST00000359597
var name = info[10]; // e.g. TP53

addFeature(range, name || ensembleId);
});
});
}

var o = {
rangeChanged: function(newRange: GenomeRange) {
fetch(newRange)
.then(() => o.trigger('newdata', newRange))
.done();
},
getFeaturesInRange
};
_.extend(o, Events); // Make this an event emitter

return o;
}

module.exports = createBigBedDataSource;
4 changes: 4 additions & 0 deletions src/ContigInterval.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class ContigInterval {
this.interval.intersects(other.interval));
}

isEqual(other: Interval): boolean {
return this.contig === other.contig && this.interval.isEqual(other.interval);
}

toString(): string {
return `${this.contig}:${this.start()}-${this.stop()}`;
}
Expand Down
20 changes: 20 additions & 0 deletions src/GeneTrack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var React = require('react/addons'),
_ = require('underscore'),
d3 = require('d3'),
types = require('./types');

var GeneTrack = React.createClass({
propTypes: {
range: types.GenomeRange,
genes: React.PropTypes.array.isRequired
},
render: function(): any {
return (
<div className="genes">
{JSON.stringify(this.props.genes)}
</div>
);
}
});

module.exports = GeneTrack;
4 changes: 4 additions & 0 deletions src/Interval.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class Interval {
return value >= this.start && value <= this.stop;
}

isEqual(other: Interval): boolean {
return this.start == other.start && this.stop == other.stop;
}

clone(): Interval {
return new Interval(this.start, this.stop);
}
Expand Down
21 changes: 17 additions & 4 deletions src/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,23 @@
var React = require('react'),
Controls = require('./Controls'),
GenomeTrack = require('./GenomeTrack'),
GeneTrack = require('./GeneTrack'),
// TODO: make this an "import type" when react-tools 0.13.0 is out.
TwoBitDataSource = require('./TwoBitDataSource'),
types = require('./types');


var Root = React.createClass({
propTypes: {
referenceSource: React.PropTypes.object.isRequired
referenceSource: React.PropTypes.object.isRequired,
geneSource: React.PropTypes.object.isRequired
},
getInitialState: function(): any {
return {
contigList: [],
range: null,
basePairs: null
basePairs: null,
genes: []
}
},
componentDidMount: function() {
Expand All @@ -33,18 +36,22 @@ var Root = React.createClass({
source.on('contigs', () => {
// this is here to facilitate faster iteration
this.handleRangeChange({
contig: 'chr1',
contig: 'chr17',
start: 123456,
stop: 123500
});
});

var geneSource = this.props.geneSource;
source.on('newdata', () => { this.update() });

this.update();
},
update: function() {
this.setState({
contigList: this.props.referenceSource.contigList(),
basePairs: this.props.referenceSource.getRange(this.state.range)
basePairs: this.props.referenceSource.getRange(this.state.range),
genes: this.props.geneSource.getFeaturesInRange(this.state.range)
});
},
handleRangeChange: function(newRange: GenomeRange) {
Expand All @@ -53,6 +60,8 @@ var Root = React.createClass({

var ref = this.props.referenceSource;
ref.rangeChanged(newRange);

this.props.geneSource.rangeChanged(newRange);
},
render: function(): any {
return (
Expand All @@ -63,6 +72,10 @@ var Root = React.createClass({
<GenomeTrack range={this.state.range}
basePairs={this.state.basePairs}
onRangeChange={this.handleRangeChange} />
<GeneTrack range={this.state.range}
genes={this.state.genes}
onRangeChange={this.handleRangeChange} />

</div>
);
}
Expand Down
10 changes: 6 additions & 4 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ var React = require('react'),
TwoBit = require('./TwoBit'),
BigBed = require('./BigBed'),
Root = require('./Root'),
createTwoBitDataSource = require('./TwoBitDataSource');
createTwoBitDataSource = require('./TwoBitDataSource'),
createBigBedDataSource = require('./BigBedDataSource');

var startMs = Date.now();
// var genome = new TwoBit('http://www.biodalliance.org/datasets/hg19.2bit');
var genome = new TwoBit('/hg19.2bit');
var dataSource = createTwoBitDataSource(genome);

var ensembl = new BigBed('/ensGene.bb');
var ensemblDataSource = createBigBedDataSource(ensembl);

genome.getFeaturesInRange('chr22', 19178140, 19178170).then(basePairs => {
var endMs = Date.now();
console.log('elapsed time (ms):', endMs - startMs);
Expand All @@ -22,10 +26,8 @@ genome.getFeaturesInRange('chr22', 19178140, 19178170).then(basePairs => {
// pre-load some data to allow network-free panning
genome.getFeaturesInRange('chr1', 123000, 124000).done();

var root = React.render(<Root referenceSource={dataSource} />,
var root = React.render(<Root referenceSource={dataSource} geneSource={ensemblDataSource} />,
document.getElementById('root'));

var ensembl = new BigBed('/ensGene.bb');

window.ensembl = ensembl;
window.genome = genome;

0 comments on commit 0656f73

Please sign in to comment.