Skip to content

Commit

Permalink
features
Browse files Browse the repository at this point in the history
  • Loading branch information
gonzalofrag committed Jul 3, 2024
1 parent b70f4e9 commit 9372072
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
build
node_modules
package-lock.json
BrAPI.js
BrAPI.js
/nbproject/private/
10 changes: 10 additions & 0 deletions load-from-file.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
<div>
<label for="phenofile">Phenotype file:</label>
<input type="file" id="phenofile" name="phenofile">

</div>
<div>
<label for="featurefile">Feature file:</label>
<input type="file" id="featurefile" name="featurefile">

</div>
<div>
<canvas id="featurecanvas"></canvas>
</div>
<input type="submit" action="#" id="submit" name="submit" value="Submit">
</div>
Expand All @@ -33,6 +42,7 @@
mapFileDom: "mapfile",
genotypeFileDom: "genofile",
phenotypeFileDom: "phenofile",
featureFileDom: "featurefile",
overviewWidth: null, overviewHeight: 200,
minGenotypeAutoWidth: 600, minGenotypeAutoHeight: 600,
});
Expand Down
7 changes: 7 additions & 0 deletions sample-data/sample.features.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# fjFile = FEATURES
gene1 2H 14.3 16.2
gene2 2H 20 35
gene3 2H 49 63
gene4 2H 34 48
gene5 2H 20 54
gene6 2H 30 41
5 changes: 5 additions & 0 deletions src/Chromosome.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ export default class Chromosome {
this.name = name;
this.end = end;
this.markers = markers;
this.features = [];

this.markers.sort((a, b) => (a.position > b.position ? 1 : -1));
}

markerCount() {
return this.markers.length;
}
insertFeatures(features){
this.features = features;
this.features.sort((a, b) => (a.start > b.start ? 1 : -1));
}
}
3 changes: 3 additions & 0 deletions src/DataSet.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export default class DataSet {
markersToRenderOn(chromosomeIndex, markerStart, markerEnd) {
return this.genomeMap.markersToRenderOn(chromosomeIndex, markerStart, markerEnd);
}
featuresToRenderOn(chromosomeIndex, markerStart, markerEnd) {
return this.genomeMap.featuresToRenderOn(chromosomeIndex, markerStart, markerEnd);
}

markerAt(markerIndex) {
return this.genomeMap.markerAt(markerIndex);
Expand Down
8 changes: 8 additions & 0 deletions src/Feature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default class Feature {
constructor(name, chromosome, startPosition, endPosition) {
this.name = name;
this.chromosome = chromosome;
this.start = startPosition;
this.end = endPosition;
}
}
58 changes: 58 additions & 0 deletions src/FeatureImporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
//import Marker from './Marker';
import Feature from './Feature';
import Chromosome from './Chromosome';
import GenomeMap from './GenomeMap';

export default class FeatureImporter {
constructor() {
this.featureNames = [];
this.featureData = [];
this.chromosomeNames = new Set();
}

processFeatureFileLine(line) {
if (line.startsWith('#') || (!line || line.length === 0) || line.startsWith('\t')) {
return;
}

// Only parse our default map file lines (i.e. not the special fixes for
// exactly specifying the chromosome length)
// http://flapjack.hutton.ac.uk/en/latest/projects_&_data_formats.html#data-sets-maps-and-genotypes
const tokens = line.split('\t');
if (tokens.length === 4) {
const featureName = tokens[0];
const chromosome = tokens[1];
const startPos = tokens[2];
const endPos = tokens[3];

// Keep track of the chromosomes that we've found
this.chromosomeNames.add(chromosome);

// Create a marker object and add it to our array of markers
const feature = new Feature(featureName, chromosome, parseFloat(startPos.replace(/,/g, ''), 10), parseFloat(endPos.replace(/,/g, ''), 10));
this.featureData.push(feature);
}
}

createFeatures(genomeMap) {
genomeMap.chromosomes.forEach(chromosome => {
const chromosomeFeatures = this.featureData.filter(m => m.chromosome === chromosome.name);
chromosome.insertFeatures(chromosomeFeatures);
});
return genomeMap;
}

parseFile(fileContents, genomeMap) {
const features = fileContents.split(/\r?\n/);
for (let feature = 0; feature < features.length; feature += 1) {
this.processFeatureFileLine(features[feature]);
}

const map = this.createFeatures(genomeMap);

return map;
}

// A method which converts BrAPI markerpositions into Flapjack markers for
// rendering
}
4 changes: 4 additions & 0 deletions src/GenomeMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export default class GenomeMap {
};
}

featuresToRenderOn(chromosomeIndex, dataStart, dataEnd) {
return this.chromosomes[chromosomeIndex];
}

markerAt(dataIndex) {
const foundChromosomes = this.intervalTree.search(dataIndex, dataIndex);
const chromosome = foundChromosomes[0];
Expand Down
82 changes: 78 additions & 4 deletions src/GenotypeCanvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,22 @@ export default class GenotypeCanvas {
this.canvas.style.display = "block";
this.drawingContext = this.canvas.getContext('2d');

this.featureCanvas = document.createElement('canvas');
this.featureCanvas.width = width;
this.featureCanvas.height = height;
this.featureCanvas.style.display = "block";
this.featureDrawingContext = this.canvas.getContext('2d');

// var featureCanvas = document.getElementById('featureCanvas');

// if (!featureCanvas || !featureCanvas.getContext) {
// console.error("Canvas not supported or ID not found: featureCanvas");
// return;
// }
// var ctx1 = canvas1.getContext('2d');
// ctx1.fillStyle = 'red';
// ctx1.fillRect(10, 10, 50, 50);

this.backBuffer = document.createElement('canvas');
this.backBuffer.width = width;
this.backBuffer.height = height;
Expand All @@ -31,7 +47,7 @@ export default class GenotypeCanvas {
this.verticalScrollbar = new ScrollBar(width, this.alleleCanvasHeight() + this.scrollbarHeight,
this.scrollbarWidth, this.alleleCanvasHeight(), true);
this.horizontalScrollbar = new ScrollBar(this.alleleCanvasWidth(),
height, this.alleleCanvasWidth(), this.scrollbarHeight, false);
height, this.alleleCanvasWidth(), this.scrollbarHeight, false);

this.translatedX = 0;
this.translatedY = 0;
Expand Down Expand Up @@ -158,7 +174,12 @@ export default class GenotypeCanvas {

return mapMarkerPos;
}
calcMapFeaturePos(position, mapScaleFactor, drawStart) {
let mapFeaturePos = ((position) * (mapScaleFactor));
mapFeaturePos = drawStart > 0 ? mapFeaturePos + drawStart : mapFeaturePos;

return mapFeaturePos;
}
highlightMarker(dataWidth, markerStart, markerEnd, xPos) {
if (this.markerUnderMouse) {
const renderData = this.dataSet.markersToRenderOn(this.selectedChromosome, markerStart, markerEnd);
Expand All @@ -180,12 +201,12 @@ export default class GenotypeCanvas {
const lastMarkerPos = chromosome.markers[renderData.firstMarker + dW].position;
const scaleFactor = lastMarkerPos == 0 ? 0 /* hack for cases where variants are not positioned */ : chromosomeWidth / (lastMarkerPos - firstMarkerPos);

this.highlightMarkerName(firstMarkerPos, scaleFactor, scaleFactor == 0 ? xPos : drawStart);
//this.highlightMarkerName(firstMarkerPos, scaleFactor, scaleFactor == 0 ? xPos : drawStart);

this.drawingContext.save();

// Translate to the correct position to draw the map
this.drawingContext.translate(this.alleleCanvasXOffset, 10);
this.drawingContext.translate(this.alleleCanvasXOffset, 18);

xPos += (this.boxSize / 2);
this.drawingContext.strokeStyle = '#F00';
Expand Down Expand Up @@ -389,6 +410,13 @@ export default class GenotypeCanvas {
this.renderScrollbars();
}

renderFeature(mapCanvas, feature, mapScaleFactor, drawStart){
const mapFeatureStartPos = this.calcMapFeaturePos(feature.start, mapScaleFactor, drawStart);
const mapFeatureEndPos = this.calcMapFeaturePos(feature.end, mapScaleFactor, drawStart);
mapCanvas.fillRect(mapFeatureStartPos, 1, mapFeatureEndPos, 10);
console.log("renderFeature",feature,mapFeatureStartPos,mapFeatureEndPos);
}

renderMarker(mapCanvas, marker, genoMarkerPos, firstMarkerPos, mapScaleFactor, drawStart) {
const mapMarkerPos = this.calcMapMarkerPos(marker, firstMarkerPos, mapScaleFactor, drawStart);

Expand Down Expand Up @@ -432,12 +460,46 @@ export default class GenotypeCanvas {
this.renderMarker(this.backContext, marker, xPos, firstMarkerPos, scaleFactor, scaleFactor == 0 ? xPos : drawStart);
}
}
renderFeatures(renderData,featureData) {
const chrStart = 0;
const chrEnd = this.dataSet.genomeMap.chromosomes[this.selectedChromosome].markerCount() * this.boxSize;
const drawStart = -this.translatedX;

const chromosome = this.dataSet.genomeMap.chromosomes[this.selectedChromosome];

const potentialWidth = drawStart > 0 ? this.alleleCanvasWidth() - drawStart : this.alleleCanvasWidth();
const chromosomeWidth = Math.min(chrEnd - this.translatedX, potentialWidth, chrEnd - chrStart);

// The data array can have too many markers in it due to the gaps between
// chromosomes, this is a fudge to ensure we don't try to draw too many markers
const chromosomeMarkerWidth = Math.max(0, Math.floor(chromosomeWidth / this.boxSize));
const dataWidth = Math.min(renderData.lastMarker - renderData.firstMarker, chromosomeMarkerWidth);

const firstMarkerPos = chromosome.markers[renderData.firstMarker].position;
const lastMarkerPos = chromosome.markers[renderData.firstMarker + dataWidth].position;
const scaleFactor = lastMarkerPos == 0 ? 0 /* hack for cases where variants are not positioned */ : chromosomeWidth / (lastMarkerPos - firstMarkerPos);

// this.dataSet.genomeMap.chromosomes[this.selectedChromosome].features.forEach(feature => {
// this.renderFeature(this.backContext, feature, scaleFactor, drawStart);
// })
featureData.features.forEach(feature => {
this.renderFeature(this.backContext, feature, scaleFactor, drawStart);
})

// for (let markerIndex = renderData.firstMarker; markerIndex <= renderData.lastMarker; markerIndex += 1) {
// const marker = this.dataSet.genomeMap.chromosomes[this.selectedChromosome].markers[markerIndex];
// let xPos = drawStart + (markerIndex * this.boxSize);
// xPos += (this.boxSize / 2);
// this.renderMarker(this.backContext, marker, xPos, firstMarkerPos, scaleFactor, scaleFactor == 0 ? xPos : drawStart);
// }
}

renderChromosome(chromosomeData) {
const width = this.dataSet.genomeMap.chromosomes[this.selectedChromosome].markerCount() * this.boxSize;
this.backContext.strokeRect(-this.translatedX, 1, width, 10);
}


renderMap(markerStart, markerEnd) {
this.backContext.save();
// Set the line style for drawing the map and markers
Expand All @@ -451,13 +513,25 @@ export default class GenotypeCanvas {
this.backContext.clip(region);

// Translate to the correct position to draw the map
this.backContext.translate(this.alleleCanvasXOffset, 10);
this.backContext.translate(this.alleleCanvasXOffset, 18);

const renderData = this.dataSet.markersToRenderOn(this.selectedChromosome, markerStart, markerEnd);

const featureData = this.dataSet.featuresToRenderOn(this.selectedChromosome, markerStart, markerEnd);
this.renderChromosome(renderData);
this.renderMarkers(renderData);

this.backContext.translate(this.alleleCanvasXOffset, -18);
this.backContext.fillStyle = 'blue';


// const featureData = [
// {start:10,end:20},{start:40,end:60}
// ];
this.renderFeatures(renderData, featureData);

this.backContext.translate(this.alleleCanvasXOffset, 36);
this.backContext.strokeStyle = 'gray';
this.backContext.restore();
}

Expand Down
20 changes: 20 additions & 0 deletions src/flapjack-bytes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import GenotypeCanvas from './GenotypeCanvas';
import OverviewCanvas from './OverviewCanvas';
import CanvasController from './CanvasController';
import MapImporter from './MapImporter';
import FeatureImporter from './FeatureImporter';
import GenotypeImporter from './GenotypeImporter';
import PhenotypeImporter from './PhenotypeImporter';
import SimilarityLineSort from './sort/SimilarityLineSort';
Expand Down Expand Up @@ -30,6 +31,7 @@ export default function GenotypeRenderer() {
const boxSize = 17;

let genomeMap;
let genomeFeatures;
let phenotypes;
let traits;
let dataSet;
Expand Down Expand Up @@ -1148,6 +1150,13 @@ export default function GenotypeRenderer() {

setProgressBarLabel("Loading file contents...");
let loadingPromises = [];
let featurePromise;

if (config.featureFileDom !== undefined){
const featureFile = document.getElementById(config.featureFileDom.replace('#', '')).files[0];
featurePromise = loadFromFile(featureFile);
loadingPromises.push(featurePromise);
}

if (config.mapFileDom !== undefined){
const mapFile = document.getElementById(config.mapFileDom.replace('#', '')).files[0];
Expand All @@ -1157,6 +1166,16 @@ export default function GenotypeRenderer() {
mapPromise = mapPromise.then((result) => {
const mapImporter = new MapImporter();
genomeMap = mapImporter.parseFile(result);
if (featurePromise) {
// Load feature data
featurePromise = featurePromise.then((result) => {
const featureImporter = new FeatureImporter();
genomeFeatures = featureImporter.parseFile(result, genomeMap);
}).catch(reason => {
console.error(reason);
genomeFeatures = undefined;
});
}
}).catch(reason => {
console.error(reason);
genomeMap = undefined;
Expand All @@ -1165,6 +1184,7 @@ export default function GenotypeRenderer() {
loadingPromises.push(mapPromise);
}


if (config.phenotypeFileDom !== undefined){
const phenotypeFile = document.getElementById(config.phenotypeFileDom.replace('#', '')).files[0];
let phenotypePromise = loadFromFile(phenotypeFile);
Expand Down

0 comments on commit 9372072

Please sign in to comment.