Skip to content

Instantly share code, notes, and snippets.

@kevinschaul
Last active January 1, 2016 22:59
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kevinschaul/8213691 to your computer and use it in GitHub Desktop.
Save kevinschaul/8213691 to your computer and use it in GitHub Desktop.
Star plots in d3
d3.starPlot = function() {
var width = 200,
margin = {
top: 0,
right: 0,
bottom: 0,
left: 0
},
labelMargin = 20,
includeGuidelines = true,
includeLabels = true,
accessors = [],
labels = [],
title = nop,
g,
datum,
radius = width / 2,
origin = [radius, radius],
radii = accessors.length,
radians = 2 * Math.PI / radii,
scale = d3.scale.linear()
.domain([0, 100])
.range([0, radius])
function chart(selection) {
datum = selection.datum();
g = selection
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
if (includeGuidelines) {
drawGuidelines();
}
if (includeLabels) {
drawLabels();
}
drawChart();
}
function drawGuidelines() {
var r = 0;
accessors.forEach(function(d, i) {
var l, x, y;
l = radius;
x = l * Math.cos(r);
y = l * Math.sin(r);
g.append('line')
.attr('class', 'star-axis')
.attr('x1', origin[0])
.attr('y1', origin[1])
.attr('x2', origin[0] + x)
.attr('y2', origin[1] + y)
r += radians;
})
}
function drawLabels() {
var r = 0;
accessors.forEach(function(d, i) {
var l, x, y;
l = radius;
x = (l + labelMargin) * Math.cos(r);
y = (l + labelMargin) * Math.sin(r);
g.append('text')
.attr('class', 'star-label')
.attr('x', origin[0] + x)
.attr('y', origin[1] + y)
.text(labels[i])
.style('text-anchor', 'middle')
.style('dominant-baseline', 'central')
r += radians;
})
}
function drawChart() {
g.append('circle')
.attr('class', 'star-origin')
.attr('cx', origin[0])
.attr('cy', origin[1])
.attr('r', 2)
var path = d3.svg.line.radial()
var pathData = [];
var r = Math.PI / 2;
accessors.forEach(function(d) {
pathData.push([
scale(d(datum)),
r
])
r += radians;
});
g.append('path')
.attr('class', 'star-path')
.attr('transform', 'translate(' + origin[0] + ',' + origin[1] + ')')
.attr('d', path(pathData) + 'Z');
g.append('text')
.attr('class', 'star-title')
.attr('x', origin[0])
.attr('y', -(margin.top / 2))
.text(title(datum))
.style('text-anchor', 'middle')
}
function nop() {
return;
}
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 = [radius, radius];
scale.range([0, radius])
return chart;
};
chart.margin = function(_) {
if (!arguments.length) return margin;
margin = _;
origin = [radius, 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.includeGuidelines = function(_) {
if (!arguments.length) return includeGuidelines;
includeGuidelines = _;
return chart;
};
chart.includeLabels = function(_) {
if (!arguments.length) return includeLabels;
includeLabels = _;
return chart;
};
return chart;
}
<!DOCTYPE>
<meta charset="utf-8">
<style>
body {
width: 960px;
margin: auto;
font-family: Arial;
}
#target {
margin: 40px 0;
}
.chart {
margin-bottom: 40px;
}
.star-title {
font-size: 14px;
}
.star-label {
font-size: 11px;
}
.star-origin {
fill: #333;
}
.star-axis {
stroke: #ccc;
stroke-width: 2px;
stroke-dasharray: 4 5;
}
.star-path {
stroke: #444;
stroke-width: 2px;
fill: #709CB1;
fill-opacity: 0.6;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="d3-starPlot.js"></script>
<script>
var margin = {
top: 36,
right: 50,
bottom: 20,
left: 50
};
var width = 240 - margin.left - margin.right;
var height = 240 - margin.top - margin.bottom;
var labelMargin = 8;
var scale = d3.scale.linear()
.domain([0, 4])
.range([0, 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 star = d3.starPlot()
.width(width)
.accessors([
function(d) { return scale(d.Body); },
function(d) { return scale(d.Sweetness); },
function(d) { return scale(d.Smoky); },
function(d) { return scale(d.Honey); },
function(d) { return scale(d.Spicy); },
function(d) { return scale(d.Nutty); },
function(d) { return scale(d.Malty); },
function(d) { return scale(d.Fruity); },
function(d) { return scale(d.Floral); },
])
.labels([
'Body',
'Sweetness',
'Smoky',
'Honey',
'Spicy',
'Nutty',
'Malty',
'Fruity',
'Floral',
])
.title(function(d) { return d.Distillery; })
.margin(margin)
.labelMargin(labelMargin)
rows.forEach(function(d, i) {
star.includeLabels(i % 4 === 0 ? true : false);
d3.select('#target').append('svg')
.attr('class', 'chart')
.attr('width', width + margin.left + margin.right)
.attr('height', width + margin.top + margin.bottom)
.append('g')
.datum(d)
.call(star)
});
});
</script>
<div id='target'></div>
</body>
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 ArranIsleOf 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 Belvenie 3 2 1 0 0 3 2 1 0 2 2 2 AB55 4DH 332680 840840
13 BenNevis 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 BlairAthol 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 GlenDeveronMacduff 2 3 1 1 1 1 1 2 0 2 0 1 AB4 3JT 372120 860400
34 GlenElgin 2 3 1 0 0 2 1 1 1 1 2 3 IV30 3SL 322640 861040
35 GlenGarioch 2 1 3 0 0 0 3 1 0 2 2 2 AB51 0ES 381020 827590
36 GlenGrant 1 2 0 0 0 1 0 1 2 1 2 1 AB38 7BS 327610 849570
37 GlenKeith 2 3 1 0 0 1 2 1 2 1 2 1 AB55 3BU 340754 848623
38 GlenMoray 1 2 1 0 0 1 2 1 2 2 2 4 IV30 1YE 319820 862320
39 GlenOrd 3 2 1 0 0 1 2 1 1 2 2 2 IV6 7UJ 251810 850860
40 GlenScotia 2 2 2 2 0 1 0 1 2 2 1 1 PA28 6DS 172090 621010
41 GlenSpey 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 OldFettercairn 1 2 2 0 1 2 2 1 2 3 1 1 AB30 1YE 370860 772900
69 OldPulteney 2 1 2 2 1 0 1 1 2 2 2 2 KW1 5BA 336730 950130
70 RoyalBrackla 2 3 2 1 1 1 2 1 0 2 3 2 IV12 5QY 286040 851320
71 RoyalLochnagar 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment