Minor updates to Kevin Schaul's reusable radar chart of whiskey flavors.
Data source: https://www.mathstat.strath.ac.uk/outreach/nessie/nessie_whisky.html
Minor updates to Kevin Schaul's reusable radar chart of whiskey flavors.
Data source: https://www.mathstat.strath.ac.uk/outreach/nessie/nessie_whisky.html
<!DOCTYPE> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
width: 960px; | |
margin: auto; | |
font-family: Helvetica; | |
} | |
.chart { | |
margin-bottom: 40px; | |
} | |
.radar-title { | |
font-size: 18px; | |
font-weight: bold; | |
fill: #333; | |
} | |
.radar-label { | |
font-size: 11px; | |
fill: #666; | |
} | |
.radar-origin { | |
fill: #999; | |
} | |
.radar-axis { | |
stroke: #999; | |
stroke-width: 1px; | |
stroke-dasharray: 1 2; | |
} | |
.radar-path { | |
stroke: #333; | |
stroke-width: 1px; | |
fill: #333; | |
fill-opacity: 0.75; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="radar.js"></script> | |
<script> | |
var width = 140; | |
var margin = 50; | |
var labelMargin = 10; | |
var scale = d3.scale.linear() | |
.domain([0, 5]) | |
.range([5, 100]) | |
d3.csv('whiskies.csv') | |
.row(function(d) { | |
d.Body = +d.Body; | |
d.Sweetness = +d.Sweetness; | |
d.Smoky = +d.Smoky; | |
d.Medicinal = +d.Medicinal; | |
d.Tobacco = +d.Tobacco; | |
d.Honey = +d.Honey; | |
d.Spicy = +d.Spicy; | |
d.Winey = +d.Winey; | |
d.Nutty = +d.Nutty; | |
d.Malty = +d.Malty; | |
d.Fruity = +d.Fruity; | |
d.Floral = +d.Floral; | |
return d; | |
}) | |
.get(function(error, rows) { | |
var radar = radarChart() | |
.width(width) | |
.accessors([ | |
function(d) { return scale(d.Body); }, | |
function(d) { return scale(d.Smoky); }, | |
function(d) { return scale(d.Tobacco); }, | |
function(d) { return scale(d.Medicinal); }, | |
function(d) { return scale(d.Winey); }, | |
function(d) { return scale(d.Spicy); }, | |
function(d) { return scale(d.Malty); }, | |
function(d) { return scale(d.Nutty); }, | |
function(d) { return scale(d.Honey); }, | |
function(d) { return scale(d.Sweetness); }, | |
function(d) { return scale(d.Fruity); }, | |
function(d) { return scale(d.Floral); }, | |
]) | |
.labels([ | |
'Body', | |
'Smoky', | |
'Tobacco', | |
'Medicinal', | |
'Winey', | |
'Spicy', | |
'Malty', | |
'Nutty', | |
'Honey', | |
'Sweetness', | |
'Fruity', | |
'Floral', | |
]) | |
.title(function(d) { return (d.Distillery); }) | |
.margin(margin) | |
.labelMargin(labelMargin) | |
rows.forEach(function(d) { | |
d3.select('body').append('svg') | |
.attr('class', 'chart') | |
.attr('height', width + (2 * margin)) | |
.attr('width', width + (2 * margin)) | |
.append('g') | |
.attr('transform', 'translate(' + margin / 2 + ',' + margin / 2 + ')') | |
.datum(d) | |
.call(radar) | |
radar.includeAxis(true); | |
}); | |
}); | |
</script> | |
</body> |
function radarChart() { | |
var width = 400; | |
var margin = 0; | |
var labelMargin = 0; | |
var includeAxis = true; | |
var accessors = []; | |
var labels = []; | |
var title = function(d) { return; }; | |
var g; | |
var datum; | |
var radius = width / 2; | |
var origin = margin + radius; | |
var radii = accessors.length; | |
var radians = 2 * Math.PI / radii; | |
function chart(selection) { | |
datum = selection.datum(); | |
g = selection.append('g'); | |
if (includeAxis) { | |
drawAxis(); | |
} | |
drawChart(); | |
} | |
chart.accessors = function(_) { | |
if (!arguments.length) return accessors; | |
accessors = _; | |
radii = accessors.length; | |
radians = 2 * Math.PI / radii; | |
return chart; | |
}; | |
chart.width = function(_) { | |
if (!arguments.length) return width; | |
width = _; | |
radius = width / 2; | |
origin = margin + radius; | |
return chart; | |
}; | |
chart.margin = function(_) { | |
if (!arguments.length) return margin; | |
margin = _; | |
origin = margin + radius; | |
return chart; | |
}; | |
chart.labelMargin = function(_) { | |
if (!arguments.length) return labelMargin; | |
labelMargin = _; | |
return chart; | |
}; | |
chart.title = function(_) { | |
if (!arguments.length) return title; | |
title = _; | |
return chart; | |
}; | |
chart.labels = function(_) { | |
if (!arguments.length) return labels; | |
labels = _; | |
return chart; | |
}; | |
chart.includeAxis = function(_) { | |
if (!arguments.length) return includeAxis; | |
includeAxis = _; | |
return chart; | |
}; | |
function drawAxis() { | |
var r = 0; | |
accessors.forEach(function(d, i) { | |
var x = radius * Math.cos(r); | |
var y = radius * Math.sin(r); | |
g.append('line') | |
.attr('class', 'radar-axis') | |
.attr('x1', origin) | |
.attr('y1', origin) | |
.attr('x2', origin + x) | |
.attr('y2', origin + y) | |
x = (radius + labelMargin) * Math.cos(r); | |
y = (radius + labelMargin) * Math.sin(r); | |
g.append('text') | |
.attr('class', 'radar-label') | |
.attr('x', origin + x) | |
.attr('y', origin + y) | |
.text(labels[i]) | |
.style('text-anchor', 'middle') | |
.style('dominant-baseline', 'central') | |
r += radians; | |
}) | |
} | |
function drawChart() { | |
g.append('circle') | |
.attr('class', 'radar-origin') | |
.attr('cx', origin) | |
.attr('cy', origin) | |
.attr('r', 2) | |
var path = d3.svg.line.radial() | |
var scale = d3.scale.linear() | |
.domain([0, 100]) | |
.range([0, radius]) | |
var pathData = []; | |
var r = Math.PI / 2; | |
accessors.forEach(function(d) { | |
pathData.push([ | |
scale(d(datum)), | |
r | |
]) | |
r += radians; | |
}); | |
g.append('path') | |
.attr('class', 'radar-path') | |
.attr('transform', 'translate(' + origin + ',' + origin + ')') | |
.attr('d', path(pathData) + 'Z'); | |
g.append('text') | |
.attr('class', 'radar-title') | |
.attr('x', origin) | |
.attr('y', 0) | |
.text(title(datum)) | |
.style('text-anchor', 'middle') | |
} | |
return chart; | |
} |
RowID | Distillery | Body | Sweetness | Smoky | Medicinal | Tobacco | Honey | Spicy | Winey | Nutty | Malty | Fruity | Floral | Postcode | Latitude | Longitude | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
01 | Aberfeldy | 2 | 2 | 2 | 0 | 0 | 2 | 1 | 2 | 2 | 2 | 2 | 2 | PH15 2EB | 286580 | 749680 | |
02 | Aberlour | 3 | 3 | 1 | 0 | 0 | 4 | 3 | 2 | 2 | 3 | 3 | 2 | AB38 9PJ | 326340 | 842570 | |
03 | anCnoc | 1 | 3 | 2 | 0 | 0 | 2 | 0 | 0 | 2 | 2 | 3 | 2 | AB5 5LI | 352960 | 839320 | |
04 | Ardbeg | 4 | 1 | 4 | 4 | 0 | 0 | 2 | 0 | 1 | 2 | 1 | 0 | PA42 7EB | 141560 | 646220 | |
05 | Ardmore | 2 | 2 | 2 | 0 | 0 | 1 | 1 | 1 | 2 | 3 | 1 | 1 | AB54 4NH | 355350 | 829140 | |
06 | Arran | 2 | 3 | 1 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 2 | KA27 8HJ | 194050 | 649950 | |
07 | Auchentoshan | 0 | 2 | 0 | 0 | 0 | 1 | 1 | 0 | 2 | 2 | 3 | 3 | G81 4SJ | 247670 | 672610 | |
08 | Auchroisk | 2 | 3 | 1 | 0 | 0 | 2 | 1 | 2 | 2 | 2 | 2 | 1 | AB55 3XS | 340754 | 848623 | |
09 | Aultmore | 2 | 2 | 1 | 0 | 0 | 1 | 0 | 0 | 2 | 2 | 2 | 2 | AB55 3QY | 340754 | 848623 | |
10 | Balblair | 2 | 3 | 2 | 1 | 0 | 0 | 2 | 0 | 2 | 1 | 2 | 1 | IV19 1LB | 270820 | 885770 | |
11 | Balmenach | 4 | 3 | 2 | 0 | 0 | 2 | 1 | 3 | 3 | 0 | 1 | 2 | PH26 3PF | 307750 | 827170 | |
12 | Balvenie | 3 | 2 | 1 | 0 | 0 | 3 | 2 | 1 | 0 | 2 | 2 | 2 | AB55 4DH | 332680 | 840840 | |
13 | Ben Nevis | 4 | 2 | 2 | 0 | 0 | 2 | 2 | 0 | 2 | 2 | 2 | 2 | PH33 6TJ | 212600 | 775710 | |
14 | Benriach | 2 | 2 | 1 | 0 | 0 | 2 | 2 | 0 | 0 | 2 | 3 | 2 | IV30 8SJ | 323450 | 858380 | |
15 | Benrinnes | 3 | 2 | 2 | 0 | 0 | 3 | 1 | 1 | 2 | 3 | 2 | 2 | AB38 9NN | 325800 | 839920 | |
16 | Benromach | 2 | 2 | 2 | 0 | 0 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | IV36 3EB | 303330 | 859350 | |
17 | Bladnoch | 1 | 2 | 1 | 0 | 0 | 0 | 1 | 1 | 0 | 2 | 2 | 3 | DG8 9AB | 242260 | 554260 | |
18 | Blair Athol | 2 | 2 | 2 | 0 | 0 | 1 | 2 | 2 | 2 | 2 | 2 | 2 | PH16 5LY | 294860 | 757580 | |
19 | Bowmore | 2 | 2 | 3 | 1 | 0 | 2 | 2 | 1 | 1 | 1 | 1 | 2 | PA43 7GS | 131330 | 659720 | |
20 | Bruichladdich | 1 | 1 | 2 | 2 | 0 | 2 | 2 | 1 | 2 | 2 | 2 | 2 | PA49 7UN | 126680 | 661400 | |
21 | Bunnahabhain | 1 | 2 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 2 | 2 | 3 | PA46 7RR | 142210 | 673170 | |
22 | Caol Ila | 3 | 1 | 4 | 2 | 1 | 0 | 2 | 0 | 2 | 1 | 1 | 1 | PA46 7RL | 142920 | 670040 | |
23 | Cardhu | 1 | 3 | 1 | 0 | 0 | 1 | 1 | 0 | 2 | 2 | 2 | 2 | AB38 7RY | 318790 | 843090 | |
24 | Clynelish | 3 | 2 | 3 | 3 | 1 | 0 | 2 | 0 | 1 | 1 | 2 | 0 | KW9 6LB | 290250 | 904230 | |
25 | Craigallechie | 2 | 2 | 2 | 0 | 1 | 2 | 2 | 1 | 2 | 2 | 1 | 4 | AB38 9ST | 328920 | 844920 | |
26 | Craigganmore | 2 | 3 | 2 | 1 | 0 | 0 | 1 | 0 | 2 | 2 | 2 | 2 | AB37 9AB | 316600 | 836370 | |
27 | Dailuaine | 4 | 2 | 2 | 0 | 0 | 1 | 2 | 2 | 2 | 2 | 2 | 1 | AB38 7RE | 323520 | 841010 | |
28 | Dalmore | 3 | 2 | 2 | 1 | 0 | 1 | 2 | 2 | 1 | 2 | 3 | 1 | IV17 0UT | 266610 | 868730 | |
29 | Dalwhinnie | 2 | 2 | 2 | 0 | 0 | 2 | 1 | 0 | 1 | 2 | 2 | 2 | PH19 1AB | 263670 | 785270 | |
30 | Deanston | 2 | 2 | 1 | 0 | 0 | 2 | 1 | 1 | 1 | 3 | 2 | 1 | FK16 6AG | 271570 | 701570 | |
31 | Dufftown | 2 | 3 | 1 | 1 | 0 | 0 | 0 | 0 | 1 | 2 | 2 | 2 | AB55 4BR | 332360 | 839200 | |
32 | Edradour | 2 | 3 | 1 | 0 | 0 | 2 | 1 | 1 | 4 | 2 | 2 | 2 | PH16 5JP | 295960 | 757940 | |
33 | Glen Deveron/Macduff | 2 | 3 | 1 | 1 | 1 | 1 | 1 | 2 | 0 | 2 | 0 | 1 | AB4 3JT | 372120 | 860400 | |
34 | Glen Elgin | 2 | 3 | 1 | 0 | 0 | 2 | 1 | 1 | 1 | 1 | 2 | 3 | IV30 3SL | 322640 | 861040 | |
35 | Glen Garioch | 2 | 1 | 3 | 0 | 0 | 0 | 3 | 1 | 0 | 2 | 2 | 2 | AB51 0ES | 381020 | 827590 | |
36 | Glen Grant | 1 | 2 | 0 | 0 | 0 | 1 | 0 | 1 | 2 | 1 | 2 | 1 | AB38 7BS | 327610 | 849570 | |
37 | Glen Keith | 2 | 3 | 1 | 0 | 0 | 1 | 2 | 1 | 2 | 1 | 2 | 1 | AB55 3BU | 340754 | 848623 | |
38 | Glen Moray | 1 | 2 | 1 | 0 | 0 | 1 | 2 | 1 | 2 | 2 | 2 | 4 | IV30 1YE | 319820 | 862320 | |
39 | Glen Ord | 3 | 2 | 1 | 0 | 0 | 1 | 2 | 1 | 1 | 2 | 2 | 2 | IV6 7UJ | 251810 | 850860 | |
40 | Glen Scotia | 2 | 2 | 2 | 2 | 0 | 1 | 0 | 1 | 2 | 2 | 1 | 1 | PA28 6DS | 172090 | 621010 | |
41 | Glen Spey | 1 | 3 | 1 | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 0 | 2 | AB38 7AU | 327760 | 849140 | |
42 | Glenallachie | 1 | 3 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 2 | 2 | 2 | AB38 9LR | 326490 | 841240 | |
43 | Glendronach | 4 | 2 | 2 | 0 | 0 | 2 | 1 | 4 | 2 | 2 | 2 | 0 | AB54 6DA | 361200 | 844930 | |
44 | Glendullan | 3 | 2 | 1 | 0 | 0 | 2 | 1 | 2 | 1 | 2 | 3 | 2 | AB55 4DJ | 333000 | 840300 | |
45 | Glenfarclas | 2 | 4 | 1 | 0 | 0 | 1 | 2 | 3 | 2 | 3 | 2 | 2 | AB37 9BD | 320950 | 838160 | |
46 | Glenfiddich | 1 | 3 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 2 | 2 | AB55 4DH | 332680 | 840840 | |
47 | Glengoyne | 1 | 2 | 0 | 0 | 0 | 1 | 1 | 1 | 2 | 2 | 3 | 2 | G63 9LB | 252810 | 682750 | |
48 | Glenkinchie | 1 | 2 | 1 | 0 | 0 | 1 | 2 | 0 | 0 | 2 | 2 | 2 | EH34 5ET | 344380 | 666690 | |
49 | Glenlivet | 2 | 3 | 1 | 0 | 0 | 2 | 2 | 2 | 1 | 2 | 2 | 3 | AB37 9DB | 319560 | 828780 | |
50 | Glenlossie | 1 | 2 | 1 | 0 | 0 | 1 | 2 | 0 | 1 | 2 | 2 | 2 | IV30 3SS | 322640 | 861040 | |
51 | Glenmorangie | 2 | 2 | 1 | 1 | 0 | 1 | 2 | 0 | 2 | 1 | 2 | 2 | IV19 1PZ | 276750 | 883450 | |
52 | Glenrothes | 2 | 3 | 1 | 0 | 0 | 1 | 1 | 2 | 1 | 2 | 2 | 0 | AB38 7AA | 327650 | 849170 | |
53 | Glenturret | 2 | 3 | 1 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 1 | 2 | PH7 4HA | 285630 | 723580 | |
54 | Highland Park | 2 | 2 | 3 | 1 | 0 | 2 | 1 | 1 | 1 | 2 | 1 | 1 | KW15 1SU | 345340 | 1009260 | |
55 | Inchgower | 1 | 3 | 1 | 1 | 0 | 2 | 2 | 0 | 1 | 2 | 1 | 2 | AB56 5AB | 342610 | 863970 | |
56 | Isle of Jura | 2 | 1 | 2 | 2 | 0 | 1 | 1 | 0 | 2 | 1 | 1 | 1 | PA60 7XT | 152660 | 667040 | |
57 | Knochando | 2 | 3 | 1 | 0 | 0 | 2 | 2 | 1 | 2 | 1 | 2 | 2 | AB38 7RT | 319470 | 841570 | |
58 | Lagavulin | 4 | 1 | 4 | 4 | 1 | 0 | 1 | 2 | 1 | 1 | 1 | 0 | PA42 7DZ | 140430 | 645730 | |
59 | Laphroig | 4 | 2 | 4 | 4 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | PA42 7DU | 138680 | 645160 | |
60 | Linkwood | 2 | 3 | 1 | 0 | 0 | 1 | 1 | 2 | 0 | 1 | 3 | 2 | IV30 3RD | 322640 | 861040 | |
61 | Loch Lomond | 1 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 2 | 1 | 2 | G83 0TL | 239370 | 680920 | |
62 | Longmorn | 3 | 2 | 1 | 0 | 0 | 1 | 1 | 1 | 3 | 3 | 2 | 3 | IV30 3SJ | 322640 | 861040 | |
63 | Macallan | 4 | 3 | 1 | 0 | 0 | 2 | 1 | 4 | 2 | 2 | 3 | 1 | AB38 9RX | 327710 | 844480 | |
64 | Mannochmore | 2 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 2 | 1 | 2 | 2 | IV30 3SS | 322640 | 861040 | |
65 | Miltonduff | 2 | 4 | 1 | 0 | 0 | 1 | 0 | 0 | 2 | 1 | 1 | 2 | IV30 3TQ | 322640 | 861040 | |
66 | Mortlach | 3 | 2 | 2 | 0 | 0 | 2 | 3 | 3 | 2 | 1 | 2 | 2 | AB55 4AQ | 332950 | 839850 | |
67 | Oban | 2 | 2 | 2 | 2 | 0 | 0 | 2 | 0 | 2 | 2 | 2 | 0 | PA34 5NH | 185940 | 730190 | |
68 | Old Fettercairn | 1 | 2 | 2 | 0 | 1 | 2 | 2 | 1 | 2 | 3 | 1 | 1 | AB30 1YE | 370860 | 772900 | |
69 | Old Pulteney | 2 | 1 | 2 | 2 | 1 | 0 | 1 | 1 | 2 | 2 | 2 | 2 | KW1 5BA | 336730 | 950130 | |
70 | Royal Brackla | 2 | 3 | 2 | 1 | 1 | 1 | 2 | 1 | 0 | 2 | 3 | 2 | IV12 5QY | 286040 | 851320 | |
71 | Royal Lochnagar | 3 | 2 | 2 | 0 | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 1 | AB35 5TB | 326140 | 794370 | |
72 | Scapa | 2 | 2 | 1 | 1 | 0 | 2 | 1 | 1 | 2 | 2 | 2 | 2 | KW15 1SE | 342850 | 1008930 | |
73 | Speyburn | 2 | 4 | 1 | 0 | 0 | 2 | 1 | 0 | 0 | 2 | 1 | 2 | AB38 7AG | 326930 | 851430 | |
74 | Speyside | 2 | 2 | 1 | 0 | 0 | 1 | 0 | 1 | 2 | 2 | 2 | 2 | PH21 1NS | 278740 | 800600 | |
75 | Springbank | 2 | 2 | 2 | 2 | 0 | 2 | 2 | 1 | 2 | 1 | 0 | 1 | PA28 6EJ | 172280 | 620910 | |
76 | Strathisla | 2 | 2 | 1 | 0 | 0 | 2 | 2 | 2 | 3 | 3 | 3 | 2 | AB55 3BS | 340754 | 848623 | |
77 | Strathmill | 2 | 3 | 1 | 0 | 0 | 0 | 2 | 0 | 2 | 1 | 3 | 2 | AB55 5DQ | 342650 | 850500 | |
78 | Talisker | 4 | 2 | 3 | 3 | 0 | 1 | 3 | 0 | 1 | 2 | 2 | 0 | IV47 8SR | 137950 | 831770 | |
79 | Tamdhu | 1 | 2 | 1 | 0 | 0 | 2 | 0 | 1 | 1 | 2 | 2 | 2 | AB38 7RP | 319210 | 841760 | |
80 | Tamnavulin | 1 | 3 | 2 | 0 | 0 | 0 | 2 | 0 | 2 | 1 | 2 | 3 | AB37 9JA | 321180 | 826110 | |
81 | Teaninich | 2 | 2 | 2 | 1 | 0 | 0 | 2 | 0 | 0 | 0 | 2 | 2 | IV17 0XB | 265360 | 869120 | |
82 | Tobermory | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 2 | 2 | 2 | PA75 6NR | 150450 | 755070 | |
83 | Tomatin | 2 | 3 | 2 | 0 | 0 | 2 | 2 | 1 | 1 | 2 | 0 | 1 | IV13 7YT | 279120 | 829630 | |
84 | Tomintoul | 0 | 3 | 1 | 0 | 0 | 2 | 2 | 1 | 1 | 2 | 1 | 2 | AB37 9AQ | 315100 | 825560 | |
85 | Tormore | 2 | 2 | 1 | 0 | 0 | 1 | 0 | 1 | 2 | 1 | 0 | 0 | PH26 3LR | 315180 | 834960 | |
86 | Tullibardine | 2 | 3 | 0 | 0 | 1 | 0 | 2 | 1 | 1 | 2 | 2 | 1 | PH4 1QG | 289690 | 708850 |