Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: cropgeeks/flapjack-bytes
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: warelab/flapjack-bytes
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 4 commits
  • 11 files changed
  • 2 contributors

Commits on Jul 3, 2024

  1. features

    gonzalofrag committed Jul 3, 2024
    Copy the full SHA
    9372072 View commit details

Commits on Jul 10, 2024

  1. updating one file

    gonzalofrag committed Jul 10, 2024
    Copy the full SHA
    863acd3 View commit details
  2. Copy the full SHA
    83b6967 View commit details

Commits on Aug 2, 2024

  1. fixed calc feature pos

    ajo2995 committed Aug 2, 2024
    Copy the full SHA
    bbccf24 View commit details
Showing with 239 additions and 22 deletions.
  1. +2 −1 .gitignore
  2. +10 −0 load-from-file.html
  3. +5 −5 load-from-url.html
  4. +7 −0 sample-data/sample.features.txt
  5. +5 −0 src/Chromosome.js
  6. +3 −0 src/DataSet.js
  7. +8 −0 src/Feature.js
  8. +58 −0 src/FeatureImporter.js
  9. +4 −0 src/GenomeMap.js
  10. +84 −10 src/GenotypeCanvas.js
  11. +53 −6 src/flapjack-bytes.js
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
@@ -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>
@@ -33,6 +42,7 @@
mapFileDom: "mapfile",
genotypeFileDom: "genofile",
phenotypeFileDom: "phenofile",
featureFileDom: "featurefile",
overviewWidth: null, overviewHeight: 200,
minGenotypeAutoWidth: 600, minGenotypeAutoHeight: 600,
});
10 changes: 5 additions & 5 deletions load-from-url.html
Original file line number Diff line number Diff line change
@@ -7,15 +7,15 @@
<div>
<div>
<label for="mapfile">Map file:</label>
<input type="text" id="mapfile" name="mapfile" value="http://bioinf.hutton.ac.uk/flapjack/sample-data/tutorials/ped-ver-tutorial.map">
<input type="text" id="mapfile" name="mapfile" value="http://gorgonzola.cshl.edu/flapjack-bytes/sample-data/sample.map">
</div>
<div>
<label for="genofile">Genotype file:</label>
<input type="text" id="genofile" name="genofile" value="http://bioinf.hutton.ac.uk/flapjack/sample-data/tutorials/ped-ver-tutorial.dat">
<input type="text" id="genofile" name="genofile" value="http://gorgonzola.cshl.edu/flapjack-bytes/sample-data/sample.dat">
</div>
<div>
<label for="phenofile">Phenotype file:</label>
<input type="text" id="phenofile" name="phenofile">
<label for="featurefile">Feature file:</label>
<input type="text" id="featurefile" name="featurefile" value="http://gorgonzola.cshl.edu/flapjack-bytes/sample-data/sample.features.txt">
</div>
<input type="submit" action="#" id="submit" name="submit" value="Submit">
</div>
@@ -33,7 +33,7 @@
height: 600,
mapFileURL: document.getElementById('mapfile').value,
genotypeFileURL: document.getElementById('genofile').value,
phenotypeFileURL: document.getElementById('phenofile').value,
featureFileURL: document.getElementById('featurefile').value,
});
return false;
});
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
@@ -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
@@ -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);
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
@@ -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];
94 changes: 84 additions & 10 deletions src/GenotypeCanvas.js
Original file line number Diff line number Diff line change
@@ -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;
@@ -158,7 +174,12 @@ export default class GenotypeCanvas {

return mapMarkerPos;
}
calcMapFeaturePos(position, firstMarkerPos, mapScaleFactor, drawStart) {
let mapFeaturePos = ((position - firstMarkerPos) * (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);
@@ -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';
@@ -248,7 +269,7 @@ export default class GenotypeCanvas {
if (this.dataSet.hasTraits() && this.lineUnderMouse !== undefined){
this.drawingContext.save();
this.drawingContext.translate(0, this.mapCanvasHeight);

// Prevent line name under scrollbar being highlighted
const region = new Path2D();
const clipHeight = this.canScrollX() ? this.alleleCanvasHeight() : this.alleleUsedHeight();
@@ -389,6 +410,12 @@ export default class GenotypeCanvas {
this.renderScrollbars();
}

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

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

@@ -424,6 +451,7 @@ export default class GenotypeCanvas {
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);
console.log("renderMarkers scaleFactor",scaleFactor);

for (let markerIndex = renderData.firstMarker; markerIndex <= renderData.lastMarker; markerIndex += 1) {
const marker = this.dataSet.genomeMap.chromosomes[this.selectedChromosome].markers[markerIndex];
@@ -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);
console.log("renderFeatures scaleFactor",scaleFactor);
// 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, firstMarkerPos, 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
@@ -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();
}

@@ -567,7 +641,7 @@ export default class GenotypeCanvas {
this.backContext.fillStyle = trait.getColor(phenotype);
//this.backContext.fillStyle = "rgb(" + Math.floor(rgb[0] * 255) + "," + Math.floor(rgb[1] * 255) + "," + Math.floor(rgb[2] * 255) + ")";
this.backContext.fillRect(xPos, yPos, this.traitValueColumnWidths[traitIndex], this.boxSize);

this.backContext.fillStyle = "#333";
const y = yPos + (this.boxSize - (this.fontSize / 2));
this.backContext.fillText(traitValue.toString(), xPos + this.scorePadding, y);
@@ -637,7 +711,7 @@ export default class GenotypeCanvas {
const stamp = this.colorScheme.getState(germplasm, this.selectedChromosome, marker);

this.backContext.drawImage(stamp, xPos, yPos);
}
}
}
this.backContext.restore();
}
@@ -982,7 +1056,7 @@ export default class GenotypeCanvas {
if (this.dataSet.hasTraits()){
//this.traitCanvasWidth = this.displayTraits.length * this.traitBoxWidth;
this.traitValueColumnWidths = this.displayTraits.map(name => this.backContext.measureText(this.dataSet.getTrait(name).longestValue).width + 2*this.scorePadding);

if (this.traitValueColumnWidths.length == 0) this.traitValuesCanvasWidth = 0;
else this.traitValuesCanvasWidth = this.traitValueColumnWidths.reduce((a, b) => a + b);

@@ -1011,7 +1085,7 @@ export default class GenotypeCanvas {

updateScrollBars() {
this.updateScrollBarSizes();

const scrollWidth = this.alleleCanvasWidth() - this.horizontalScrollbar.widget.width;
const scrollX = Math.floor(this.mapToRange(this.translatedX, 0, this.maxCanvasWidth() - this.alleleCanvasWidth(), 0, scrollWidth));
this.horizontalScrollbar.move(scrollX, this.horizontalScrollbar.y);
@@ -1023,7 +1097,7 @@ export default class GenotypeCanvas {

zoom(size) {
const newBoxSize = parseInt(size);

// oldPosition * zoomFactor = newPosition => zoomFactor = newBoxSize / oldBoxSize
const zoomFactor = newBoxSize / this.boxSize;
this.boxSize = newBoxSize;
@@ -1098,7 +1172,7 @@ export default class GenotypeCanvas {
} else {
this.translatedY = Math.min(this.translatedY, this.maxDataHeight() - this.alleleCanvasHeight());
}

this.prerender(true);
}

Loading