Skip to content

Instantly share code, notes, and snippets.

@laceysanderson
Forked from mbostock/.block
Last active January 4, 2017 03:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save laceysanderson/0173ae42017a47665e2e to your computer and use it in GitHub Desktop.
Save laceysanderson/0173ae42017a47665e2e to your computer and use it in GitHub Desktop.
PCoA Plot

This GIST shows how to make a D3.js scatterplot visualize Principal component analysis (PCoA) results. It requires two input files:

  • PCoA.tsv: a tab-delimited copy of your PCoA results. Make sure to change the heading to be name and then p1, p2, etc. for each additional axis.
  • PCoA_groups.tsv: a tab-delimited mapping between your individual names from the first file and which group they're from. This is used to build the colour coding and legend that you see in the graph.

Make sure to include the headings exactly as they are in the example files as they are used to access the data.

You can see this gist in action over at bl.ocks.org.

This scatterplot is adapted from Mike Bostock’s General Scatterplot Example and uses d3-tip to provide pop-up information on individual lines.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.dot {
stroke: #000;
}
.d3-tip {
line-height: 1;
font-weight: bold;
padding: 12px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
border-radius: 2px;
}
/* Creates a small triangle extender for the tooltip */
.d3-tip:after {
box-sizing: border-box;
display: inline;
font-size: 10px;
width: 100%;
line-height: 1;
color: rgba(0, 0, 0, 0.8);
content: "\25BC";
position: absolute;
text-align: center;
}
/* Style northward tooltips differently */
.d3-tip.n:after {
margin: -1px 0 0 0;
top: 100%;
left: 0;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
// Open both the PCoA data and grouping files.
d3.tsv("PCoA.tsv", function(error, data) {
if (error) throw error;
d3.tsv("PCoA_groups.tsv", function(error, groupData) {
if (error) throw error;
// Define the sizes and margins for our canvas.
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// Cast my values as numbers and determine ranges.
var minmax = {p1: {min:0, max:0}, p2: {min:0, max:0}}
data.forEach(function(d) {
d.p1 = +d.p1;
d.p2 = +d.p2;
minmax.p1.min = Math.min(d.p1, minmax.p1.min);
minmax.p1.max = Math.max(d.p1, minmax.p1.max);
minmax.p2.min = Math.min(d.p2, minmax.p2.min);
minmax.p2.max = Math.max(d.p2, minmax.p2.max);
});
// Set-up my x scale.
var x = d3.scale.linear()
.range([0, width])
.domain([Math.floor(minmax.p1.min), Math.ceil(minmax.p1.max)]);
// Set-up my y scale.
var y = d3.scale.linear()
.range([height, 0])
.domain([Math.floor(minmax.p2.min), Math.ceil(minmax.p2.max)]);
// Create my x-axis using my scale.
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
// Create my y-axis using my scale.
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// Set-up my colours/groups.
var color = d3.scale.category10();
var groups = {};
groupData.forEach(function(d) {
groups[d.line] = d.group;
});
// Create my tooltip creating function.
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return "<strong>" + d.name + "</strong> (" + groups[d.name] + ")";
});
// Actually create my canvas.
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Initialize my tooltip.
svg.call(tip);
// Draw my x-axis.
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + y(0) + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("Coord. 1");
// Draw my y-axis.
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + x(0) + ",0)")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Coord. 2");
// Create all the data points :-D.
svg.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3.5)
.attr("cx", function(d) { return x(d.p1); })
.attr("cy", function(d) { return y(d.p2); })
.style("stroke", function(d) { return color(groups[d.name]); })
.style("fill", function(d) { return color(groups[d.name]); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide);
// Create the container for the legend if it doesn't already exist.
var legend = svg.selectAll(".legend")
.data(color.domain())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
// Draw the coloured rectangles for the legend.
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
// Draw the labels for the legend.
legend.append("text")
.attr("x", width - 24)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
});
});
</script>
name p1 p2 p3 p4 p5 p6
Rose Reber 0.626 1.016 2.195 -1.662 -0.533 1.256
Pansy Paisley -1.026 -0.272 2.083 0.688 -1.270 -1.770
Nathaniel Nace -0.182 3.786 2.599 -1.688 1.442 -0.679
Leon Leblanc 2.522 4.166 -1.782 3.723 1.867 1.240
Verla Vanish 1.997 3.576 -1.288 1.729 0.731 0.310
Shona Sigmon 1.960 3.719 -1.421 1.785 0.777 0.265
Columbus Cartee 2.057 3.908 -2.608 3.596 2.256 1.528
Sunni Stalzer -2.481 -2.642 0.234 1.690 1.484 0.501
Wes Wahl 2.487 3.942 -1.664 3.296 2.371 1.096
Moriah Magrath 4.037 -2.110 -1.063 -0.143 -1.076 0.850
Xavier Xavier 2.416 4.031 -1.834 3.843 1.891 1.526
Heidy Halas 2.454 3.990 -1.549 3.383 1.955 1.441
Tyrell Tenny 2.378 4.091 -1.621 3.614 2.026 1.406
Aiko Aleshire -0.860 3.607 0.641 0.268 -1.622 -1.482
Odell Orellana -0.198 -0.307 1.131 1.418 0.040 -1.581
Dane Divis -2.204 -3.173 1.983 2.022 0.506 -0.295
Etha Eagles -2.679 -2.528 0.700 1.214 -1.133 0.012
Rikki Runyon 2.358 4.759 -2.318 2.610 1.030 0.562
Gwen Ginn -1.524 2.372 1.223 0.439 -1.696 -1.984
Blaine Barriere -1.418 2.040 2.589 0.121 -0.648 -1.290
Andrea Aguiar 2.256 -1.396 -0.075 0.160 1.503 0.601
Nestor Nunes -0.380 -0.823 1.502 0.954 0.199 -1.461
Tegan Tumlinson -2.140 -3.312 0.451 2.511 0.438 -0.294
Britteny Balmer 3.158 -2.413 -2.046 -0.871 -0.030 0.986
Paulina Payne 1.251 -2.284 -0.766 -0.613 -0.992 2.205
Willodean Wurtz 3.527 -1.549 -0.051 -0.890 -0.138 1.225
line group
Rose Reber Group1
Pansy Paisley Group1
Nathaniel Nace Group1
Leon Leblanc Group1
Verla Vanish Group2
Shona Sigmon Group2
Columbus Cartee Group2
Sunni Stalzer Group2
Wes Wahl Group2
Moriah Magrath Group2
Xavier Xavier Group3
Heidy Halas Group3
Tyrell Tenny Group3
Aiko Aleshire Group3
Odell Orellana Group3
Dane Divis Group3
Etha Eagles Group4
Rikki Runyon Group4
Gwen Ginn Group4
Blaine Barriere Group4
Andrea Aguiar Group4
Nestor Nunes Group4
Tegan Tumlinson Group5
Britteny Balmer Group5
Paulina Payne Group5
Willodean Wurtz Group5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment