Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Variants and Features GA4GH, with GA4GH example file #464

Merged
merged 3 commits into from
Jul 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos for isolating all these GA4GH integration parts into a separate example 🙇


## 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