Skip to content

Instantly share code, notes, and snippets.

@mattmakesmaps
Last active December 18, 2015 04:29
Show Gist options
  • Save mattmakesmaps/5725584 to your computer and use it in GitHub Desktop.
Save mattmakesmaps/5725584 to your computer and use it in GitHub Desktop.
Coffee flavor profiles by brew method.

This d3 visualization represents Scott Rao's great graph depicting the relationship between different coffee brew methods and flavor profiles.

Brew methods to the left have the Most Body, Least Flavor Clarity, while brew methods to the right have the Least Body, Most Flavor Clarity. Larger circles represent a greater range in filter porosity.

Specifically, this is based on, via, and ripped off from.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
</head>
<body>
<script type="text/javascript">
var dataset = [
{"value": 4, "label": "Turkish", "color": "#000000"},
{"value": 6, "label": "French Press", "color": "#D8BFD8"},
{"value": 6, "label": "Eva Solo", "color": "#FF69B4"},
{"value": 10, "label": "Metal-Filter Drip", "color": "#F0E68C"},
{"value": 5, "label": "Cloth-Filter Drip", "color": "#87CEFA"},
{"value": 5, "label": "Paper-Filer Drip", "color": "#FFA500"},
{"value": 8, "label": "Siphon", "color": "#90EE90"},
{"value": 5, "label": "Chemex", "color": "#F0E68C"},
];
var w = 960;
var h = 500;
var padding = w * 0.10 //padding is 10% the width.
var svg = d3.select("body")
.append("svg")
.attr({
"width": w,
"height": h
});
var circles = svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
var xScale = d3.scale.linear()
// Need to call max domain value to length-1 since we're
// using the scale on the index, not the data value.
// e.g. circles[0][7]. 7 is a pointer to the 8th element in the array.
.domain([0, (dataset.length - 1)])
.range([padding, w-padding])
circles.attr({
"cx": function(d , i){ return xScale(i); },
"cy": h/2,
// radius is scaled in relation to 1.2% of SVG Width
"r": function(d) { return d["value"] * (w * 0.012); },
"fill": function(d){ return d["color"]; },
"stroke": function(d){ return d["color"]; },
"stroke-width": 6,
"fill-opacity": 0.75
});
//Give our Turkish Coffee a dashed line
d3.select(circles[0][0])
.attr({
"stroke-dasharray": "12,4",
"fill-opacity": 0.0
})
function makeMarker (inElement, inID, orientAngle) {
inElement.append("defs").append("marker")
.attr({
"id": inID,
"refX": 6,
"refY": 3,
"markerWidth": 25,
"markerHeight": 35,
"orient": orientAngle
})
.append("path")
.attr("d", "M 0,0 V 6 L8,3 Z");
};
makeMarker(svg, "arrow_start", 180);
makeMarker(svg, "arrow_end", "auto");
var centerline = svg.append("line")
.attr({
"x1": padding * 0.1,
"x2": w-(padding * 0.1),
"y1": h/2,
"y2": h/2,
"marker-end": "url(#arrow_end)",
"marker-start": "url(#arrow_start)"
})
.style("stroke", "black")
.style("stroke-width", 2);
var labels = svg.selectAll("text")
.data(dataset)
.enter()
.append("text")
labels.text(function(d) {
return d["label"];
})
.attr("x", function(d , i){
return xScale(i) ;
})
.attr("y", function(d, i) {
// Stagger label placement above and below circles.
if (i % 2 == 0) {
// Example: 300 - (4 * 5) - 165 = 115
return h - (d["value"] * (w * 0.012)) - (h * 0.53);
} else {
return d["value"] * (w * 0.012) + (h * 0.54)
}
})
.attr("text-anchor", "middle")
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", "#000000");
function makeAxisLabels(inElement, inText, inAnchor, inX, inY) {
inElement.append("text")
.text(inText)
.attr("x", inX)
.attr("y", inY)
.attr("text-anchor", inAnchor)
.attr("font-family", "sans-serif")
.attr("font-size", "16px")
.attr("fill", "#000000");
}
makeAxisLabels(svg, "Least Flavor Clarity", "start", 50, 435);
makeAxisLabels(svg, "Most Body", "start", 50, 455);
makeAxisLabels(svg, "Most Flavor Clarity", "end", w-50, 435);
makeAxisLabels(svg, "Least Body", "end", w-50, 455);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment