Skip to content

Commit

Permalink
Merge pull request #464 from akmorrow13/otherGA4GH
Browse files Browse the repository at this point in the history
Added Variants and Features GA4GH, with GA4GH example file
  • Loading branch information
armish committed Jul 23, 2017
2 parents 3859912 + 0bff6d2 commit 5c78282
Show file tree
Hide file tree
Showing 45 changed files with 1,371 additions and 113 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![Build Status](https://travis-ci.org/hammerlab/pileup.js.svg?branch=travis-flow)](https://travis-ci.org/hammerlab/pileup.js) [![Coverage Status](https://coveralls.io/repos/hammerlab/pileup.js/badge.svg?branch=master)](https://coveralls.io/r/hammerlab/pileup.js?branch=master) [![NPM version](http://img.shields.io/npm/v/pileup.svg)](https://www.npmjs.org/package/pileup) [![Dependency Status](https://david-dm.org/hammerlab/pileup.js.svg?theme=shields.io)](https://david-dm.org/hammerlab/pileup.js) [![devDependency Status](https://david-dm.org/hammerlab/pileup.js/dev-status.svg?theme=shields.io)](https://david-dm.org/hammerlab/pileup.js#info=devDependencies) [![DOI](https://zenodo.org/badge/8220/hammerlab/pileup.js.svg)](https://zenodo.org/badge/latestdoi/8220/hammerlab/pileup.js)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hammerlab/pileup.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/hammerlab/pileup.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)

# pileup.js
pileup.js is an interactive in-browser track viewer. [**Try a demo**][demo]!
Expand Down Expand Up @@ -98,6 +98,8 @@ To play with the demo, start an [http-server][hs]:

Then open [http://localhost:8080/examples/index.html](http://localhost:8080/examples/index.html) in your browser of choice.

To view integration with GA4GH schemas, view [http://localhost:8080/examples/ga4gh-example.html](http://localhost:8080/examples/ga4gh-example.html).

## Testing

Run the tests from the command line:
Expand Down
94 changes: 94 additions & 0 deletions examples/data-ga4gh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Some data for the demo.

// We are going to use the same data source for multiple tracks
var bamSource = pileup.formats.bam({
url: '/test-data/synth3.normal.17.7500000-7515000.bam',
indexUrl: '/test-data/synth3.normal.17.7500000-7515000.bam.bai'
});

// This URL points to the GA4GH Reference Server, which
// can be accessed for examples of standardized endpoints
// for genomic data. All available GA4GH endpoints can
// be found here: http://1kgenomes.ga4gh.org
var ga4ghReferenceServer = 'http://1kgenomes.ga4gh.org';

var sources = [
{
viz: pileup.viz.genome(),
isReference: true,
data: pileup.formats.twoBit({
url: 'http://www.biodalliance.org/datasets/hg19.2bit'
}),
name: 'Reference'
},
{
viz: pileup.viz.scale(),
name: 'Scale'
},
{
viz: pileup.viz.location(),
name: 'Location'
},
{
viz: pileup.viz.genes(),
data: pileup.formats.bigBed({
url: 'http://www.biodalliance.org/datasets/ensGene.bb'
}),
name: 'Genes'
},
{
viz: pileup.viz.variants(),
data: pileup.formats.GAVariant({
endpoint: ga4ghReferenceServer,
variantSetId: "WyIxa2dlbm9tZXMiLCJ2cyIsInBoYXNlMy1yZWxlYXNlIl0",
callSetIds: ["WyIxa2dlbm9tZXMiLCJ2cyIsInBoYXNlMy1yZWxlYXNlIiwiSEcwMDA5NiJd"],
killChr: true
}),
options: {
onVariantClicked: function(data) {
var content = "Variants:\n";
for (var i =0;i< data.length;i++) {
content += `${data[i].id}: Ref: ${data[i].ref}, Alt: `;
data[i].alt.forEach(alt => {
content += `${alt} `;
})
content += '\n';
}
alert(content);
},
},
name: 'Phase3 Release Variants'
},
{
viz: pileup.viz.features(),
data: pileup.formats.GAFeature({
endpoint: ga4ghReferenceServer,
featureSetId: "WyIxa2dlbm9tZXMiLCJnZW5jb2RlX3YyNGxpZnQzNyJd",
}),
name: 'gencode_v24lift37'
},
{
viz: pileup.viz.coverage(),
data: pileup.formats.GAReadAlignment({
endpoint: ga4ghReferenceServer,
readGroupId: "WyIxa2dlbm9tZXMiLCJyZ3MiLCJOQTEyODc4IiwiU1JSNjIyNDYxIl0",
killChr: true,
forcedReferenceId: "WyJOQ0JJMzciLCIxIl0"
}),
cssClass: 'normal',
name: 'Coverage'
},
{
viz: pileup.viz.pileup(),
data: pileup.formats.GAReadAlignment({
endpoint: ga4ghReferenceServer,
readGroupId: "WyIxa2dlbm9tZXMiLCJyZ3MiLCJOQTEyODc4IiwiU1JSNjIyNDYxIl0",
killChr: true,
forcedReferenceId: "WyJOQ0JJMzciLCIxIl0"
}),
cssClass: 'normal',
name: 'NA12878'
}
];

var range = {contig: 'chr1', start: 120000, stop: 125000};
20 changes: 20 additions & 0 deletions examples/ga4gh-example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!doctype html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" href="../style/pileup.css" />
<link rel="stylesheet" href="demo.css" />
</head>

<body>
<button id="jiggle">FPS test</button>
<div id="pileup"></div>
</body>

<script src="../node_modules/stats.js/build/stats.min.js"></script>
<script src="../dist/pileup.js"></script>
<!-- or:
<script src="../dist/pileup.min.js"></script>
-->

<script src="data-ga4gh.js"></script>
<script src="playground.js"></script>
5 changes: 5 additions & 0 deletions src/main/ContigInterval.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ class ContigInterval<T: (number|string)> {
};
}

round(size: number, zeroBased: boolean): ContigInterval<T> {
var newInterval = this.interval.round(size, zeroBased);
return new ContigInterval(this.contig, newInterval.start, newInterval.stop);
}

// Comparator for use with Array.prototype.sort
static compare(a: ContigInterval, b: ContigInterval): number {
if (a.contig > b.contig) {
Expand Down
7 changes: 4 additions & 3 deletions src/main/GA4GHAlignment.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ class GA4GHAlignment /* implements Alignment */ {
// https://github.com/ga4gh/schemas/blob/v0.5.1/src/main/resources/avro/reads.avdl
constructor(alignment: Object) {
this.alignment = alignment;
this.pos = alignment.alignment.position.position;
this.pos = parseInt(alignment.alignment.position.position);
this.ref = alignment.alignment.position.referenceName;
this.name = alignment.fragmentName;

this.cigarOps = alignment.alignment.cigar.map(
({operation, operationLength: length}) => ({ op: OP_MAP[operation], length }));
({operation, operationLength: length}) => ({ op: OP_MAP[operation], length: parseInt(length)})
);
this._interval = new ContigInterval(this.ref,
this.pos,
this.pos + this.getReferenceLength() - 1);
Expand Down Expand Up @@ -101,7 +102,7 @@ class GA4GHAlignment /* implements Alignment */ {
}
}

// This is exposed as a static method to facilitate an optimization in GA4GHDataSource.
// This is exposed as a static method to facilitate an optimization in GA4GHAlignmentSource.
static keyFromGA4GHResponse(alignment: Object): string {
// this.alignment.id would be appealing here, but it's not actually unique!
return alignment.fragmentName + ':' + alignment.readNumber;
Expand Down
12 changes: 12 additions & 0 deletions src/main/Interval.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@ class Interval {
return this.contains(other.start) && this.contains(other.stop);
}

// Rounds the interval to the nearest multiples of size.
// Optional minimum parameter determines the lowest
// possible value for the start of the resulting Interval.
round(size: number, zeroBased: boolean): Interval {
var minimum = zeroBased ? 0 : 1;
var roundDown = x => x - x % size;
var newStart = Math.max(minimum, roundDown(this.start)),
newStop = roundDown(this.stop + size - 1);

return new Interval(newStart, newStop);
}

clone(): Interval {
return new Interval(this.start, this.stop);
}
Expand Down
7 changes: 6 additions & 1 deletion src/main/RemoteRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import Q from 'q';
import ContigInterval from './ContigInterval';

var MONSTER_REQUEST = 5000000;

class RemoteRequest {
url: string;
cache: Object;
Expand Down Expand Up @@ -85,4 +87,7 @@ class RemoteRequest {
}
}

module.exports = RemoteRequest;
module.exports = {
RemoteRequest,
MONSTER_REQUEST: MONSTER_REQUEST
};
43 changes: 43 additions & 0 deletions src/main/data/feature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Class for parsing features.
* @flow
*/
'use strict';

import ContigInterval from '../ContigInterval';

class Feature {
id: string;
featureType: string;
contig: string;
start: number;
stop: number;
score: number;

constructor(feature: Object) {
this.id = feature.id;
this.featureType = feature.featureType;
this.contig = feature.contig;
this.start = feature.start;
this.stop = feature.stop;
this.score = feature.score;
}

static fromGA4GH(ga4ghFeature: Object): Feature {
return new Feature(
{
id: ga4ghFeature.id,
featureType: ga4ghFeature.featureType,
contig: ga4ghFeature.referenceName,
start: ga4ghFeature.start,
stop: ga4ghFeature.end,
score: 1000
});
}

intersects(range: ContigInterval<string>): boolean {
return range.intersects(new ContigInterval(this.contig, this.start, this.stop));
}
}

module.exports = Feature;
62 changes: 62 additions & 0 deletions src/main/data/variant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* Class for parsing variants.
* @flow
*/
'use strict';

import ContigInterval from '../ContigInterval';

class Variant {
contig: string;
position: number;
ref: string;
alt: string;
id: string;
//this is the biggest allele frequency for single vcf entry
//single vcf entry might contain more than one variant like the example below
//20 1110696 rs6040355 A G,T 67 PASS NS=2;DP=10;AF=0.333,0.667;AA=T;DB
majorFrequency: ?number;
//this is the smallest allel frequency for single vcf entry
minorFrequency: ?number;
vcfLine: string;


constructor(variant: Object) {
this.contig = variant.contig;
this.position = variant.position;
this.ref = variant.ref;
this.alt = variant.alt;
this.id = variant.id;
this.majorFrequency = variant.majorFrequency;
this.minorFrequency = variant.minorFrequency;
this.vcfLine = variant.vcfLine;
}

static fromGA4GH(ga4ghVariant: Object): Variant {
return new Variant(
{
contig: ga4ghVariant.referenceName,
position: ga4ghVariant.start,
id: ga4ghVariant.id,
ref: ga4ghVariant.referenceBases,
alt: ga4ghVariant.alternateBases,
majorFrequency: 0,
minorFrequency: 0, // TODO extract these
vcfLine: "" // TODO
});
}

intersects(range: ContigInterval<string>): boolean {
return intersects(this, range);
}

}

function intersects(variant: Variant, range: ContigInterval<string>): boolean {
return range.intersects(new ContigInterval(variant.contig, variant.position, variant.position + 1));
}

module.exports = {
Variant,
intersects
};
Loading

0 comments on commit 5c78282

Please sign in to comment.