Skip to content

Instantly share code, notes, and snippets.

@GeneExplorer
Last active February 18, 2017 04:47
Show Gist options
  • Save GeneExplorer/342bad7b6e40985300e98ab186803f5f to your computer and use it in GitHub Desktop.
Save GeneExplorer/342bad7b6e40985300e98ab186803f5f to your computer and use it in GitHub Desktop.
Gene Map
license: mit
{"genes": [{"name": "gene w", "stop": 230, "orientation": "forward", "start": 49}, {"name": "gene x", "stop": 305, "orientation": "forward", "start": 265}, {"name": "gene y", "stop": 440, "orientation": "forward", "start": 361}, {"name": "gene z", "stop": 620, "orientation": "reverse", "start": 500}]}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
polygon:hover { stroke: pink; stroke-width: 7px; }
rect:hover { stroke: cyan; stroke-width: 3px; }
text:hover { stroke: lightgray; }
</style>
</head>
<body>
<script>
var Orientation = {
FORWARD: 1,
REVERSE: 2,
BACKWARD: 2, // Alias for REVERSE
};
// Object Constructors
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
function GeneArrow(name, offset, width, height, orientation) {
// GeneArrow object attributes.
this.name = name;
this.offset = offset;
this.width = width;
this.height = height;
this.orientation = orientation;
if (orientation == Orientation.FORWARD)
this.color = "blue";
else
this.color = "red";
this.arrowHeadPercentWidth = 30.0; // Default arrow head % width
this.arrowHeadPercentHeight = 80.0; // Default arrow head % height
this.arrowBodyPercentHeight = 40.0; // Default arrow body % height
this.showTickMarks = false;
this.tickMarks = [];
// GeneArrow object functions.
this.points = function() {
// Create the arrow shape using 7 points.
var oX = this.offset.x;
var oY = this.offset.y;
var w = this.width;
var h = this.height;
var x1 = oX;
var x2 = oX + (1.0 - (this.arrowHeadPercentWidth / 100)) * w;
var x3 = oX + w;
var x4 = oX + (this.arrowHeadPercentWidth / 100) * w;
var y1 = oY + (0.5 - (this.arrowHeadPercentHeight / 100)/2) * h;
var y2 = oY + (0.5 - (this.arrowBodyPercentHeight / 100)/2) * h;
var y3 = oY + 0.5 * h;
var y4 = oY + (0.5 + (this.arrowBodyPercentHeight / 100)/2) * h;
var y5 = oY + (0.5 + (this.arrowHeadPercentHeight / 100)/2) * h;
if (orientation == Orientation.FORWARD)
{
return [
new Point(x1, y4),
new Point(x2, y4),
new Point(x2, y5),
new Point(x3, y3),
new Point(x2, y1),
new Point(x2, y2),
new Point(x1, y2)
];
}
else // Arrow going backwards.
{
return [
new Point(x1, y3),
new Point(x4, y5),
new Point(x4, y4),
new Point(x3, y4),
new Point(x3, y2),
new Point(x4, y2),
new Point(x4, y1)
];
}
}
this.nameTagLocation = function()
{
var xCoord = offset.x + (0.5 * width) - (this.name.length*5);
var yCoord = offset.y + (0.5 * height) + 5;
return new Point(xCoord, yCoord);
}
}
function drawGeneArrow(geneArrow, svgWidth, rangeX) {
var polygon = svg.append("polygon");
var pointData = "";
var p = geneArrow.points();
for (var i = 0; i < p.length; i++)
{
pointData += p[i].x + "," + p[i].y + " ";
}
polygon.attr("points", pointData);
polygon.attr("fill", geneArrow.color);
polygon.attr("stroke", "black");
polygon.append("title").text(geneArrow.name); // Tooltip shows gene name.
if (geneArrow.showTickMarks == true)
{
var t = geneArrow.tickMarks;
for (var j = 0; j < t.length; j++)
{
var rect = svg.append("rect");
var tickMarkHeight = geneArrow.height * (geneArrow.arrowBodyPercentHeight / 100) * 1.4;
var tickMarkX = t[j] * svgWidth / rangeX;
var tickMarkY = geneArrow.offset.y + (geneArrow.height / 2) - (tickMarkHeight / 2);
rect.attr("x", tickMarkX).attr("y", tickMarkY)
.attr("width", 6).attr("height", tickMarkHeight)
.attr("fill", "green");
var bpTag = svg.append("text");
var bpTagX = tickMarkX;
var bpTagY = tickMarkY - 5;
bpTag.text(t[j])
.attr("x", bpTagX)
.attr("y", bpTagY)
.style("font-size", 12)
.style("font-family", "Verdana");
}
}
var nameTag = svg.append("text");
var nameTagLocation = geneArrow.nameTagLocation();
nameTag.text(geneArrow.name)
.attr("x", nameTagLocation.x)
.attr("y", nameTagLocation.y)
.style("font-size", 20)
.style("font-family", "Verdana");
}
// Create the svg canvas.
var svgWidth = 960;
var svgHeight = 600;
var svg = d3.select("body").append("svg").attr("width", svgWidth).attr("height", svgHeight);
// Load and draw gene data.
d3.json("data.json", function(error, data) {
if (error) console.warn(error);
else console.log(data);
var geneArrows = [];
var genes = data.genes;
var arrowYOffset = 120;
var arrowHeight = 120;
var minX = 1000000;
var maxX = -1;
for (var i = 0; i < genes.length; i++)
{
var name = '' + genes[i].name;
var start = genes[i].start;
var stop = genes[i].stop;
if (genes[i].orientation == "forward")
var orientation = Orientation.FORWARD;
else
var orientation = Orientation.REVERSE;
var offset = new Point(start, arrowYOffset);
var arrowWidth = stop - start;
var geneArrow = new GeneArrow(name, offset, arrowWidth, arrowHeight, orientation);
geneArrow.tickMarks.push(start);
geneArrow.tickMarks.push(stop);
geneArrow.showTickMarks = true;
if (start < minX) minX = start;
if (stop > maxX) maxX = stop;
geneArrows.push(geneArrow);
}
// Normalize distances so that all gene data fits on the screen.
var svgWidth = 960;
var bufferPercentage = 16.0; // Add some buffer space at the right margin.
var rangeX = (maxX - minX) * (1 + (bufferPercentage / 100));
// Draw the dna sequence bar.
var dnaSequenceBarStartLocation = new Point(0, 220);
var dnaSequenceBar = new GeneArrow("dna sequence bar", dnaSequenceBarStartLocation, svgWidth, 100, Orientation.FORWARD);
dnaSequenceBar.color = "orange";
dnaSequenceBar.arrowHeadPercentWidth = 3;
dnaSequenceBar.arrowHeadPercentHeight = 40;
// Add interval tick marks.
var showIntervalTickMarks = true;
if (showIntervalTickMarks)
{
dnaSequenceBar.showTickMarks = true;
var intervalBasePairs = 50;
for (var k = 0; k < svgWidth; k += intervalBasePairs)
{
dnaSequenceBar.tickMarks.push(k);
}
}
drawGeneArrow(dnaSequenceBar, svgWidth, rangeX);
// Draw all the gene arrows.
for (i = 0; i < genes.length; i++)
{
geneArrows[i].offset.x = geneArrows[i].offset.x * svgWidth / rangeX;
geneArrows[i].width = geneArrows[i].width * svgWidth / rangeX;
drawGeneArrow(geneArrows[i], svgWidth, rangeX);
}
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment