Skip to content

Instantly share code, notes, and snippets.

@KoGor
Last active March 27, 2018 00:54
Show Gist options
  • Save KoGor/acacb0e7434d31db351a22b3836c93b3 to your computer and use it in GitHub Desktop.
Save KoGor/acacb0e7434d31db351a22b3836c93b3 to your computer and use it in GitHub Desktop.
Radial Opposing Stacked Bar Chart II
license: gpl-3.0
height: 800

Radial opposing stacked bar chart for four data columns.

km left_lane_nonlethal left_lane_lethal right_lane_nonlethal right_lane_lethal
1 31 0 4 2
2 29 1 13 1
3 2 1 7 1
4 21 0 11 4
5 23 2 29 3
6 17 1 22 4
7 17 2 30 1
8 26 0 7 2
9 24 5 2 2
10 10 5 4 3
11 13 0 17 5
12 22 5 30 1
13 14 2 35 0
14 2 1 11 0
15 6 4 6 5
16 14 4 16 1
17 23 0 24 2
18 20 5 12 0
19 35 1 21 5
20 9 5 33 4
21 14 2 34 2
22 18 4 0 3
23 1 3 14 4
24 2 2 16 2
25 14 1 6 2
26 27 2 22 1
27 24 5 13 2
28 12 2 4 4
29 32 5 12 1
30 27 4 34 0
31 19 0 23 1
32 27 5 17 4
33 21 5 12 1
34 22 2 30 2
35 12 0 29 2
36 8 1 5 5
37 3 3 17 1
38 29 3 23 4
39 34 2 13 1
40 28 3 19 3
41 4 3 28 1
42 12 2 31 1
43 15 2 14 5
44 19 0 27 1
45 14 4 6 2
46 21 1 20 4
47 33 4 8 2
48 2 5 31 4
49 6 0 33 5
50 33 0 30 1
51 11 4 28 3
52 21 3 31 1
53 16 4 30 5
54 13 2 7 2
55 23 5 12 4
56 30 5 0 1
57 5 4 29 3
58 12 5 26 0
59 7 2 4 0
60 1 3 6 4
61 3 3 25 1
62 27 3 28 1
63 28 3 24 2
64 24 3 1 2
65 13 5 22 3
66 5 4 17 5
67 33 5 6 2
68 16 2 4 4
69 34 1 5 3
70 31 1 20 4
71 9 5 23 2
72 3 4 33 4
73 7 4 15 5
74 24 2 1 2
75 22 4 25 0
76 21 3 21 2
77 10 3 22 1
78 20 3 33 2
79 23 2 17 0
80 16 4 19 0
81 17 3 28 4
82 35 1 9 3
83 1 2 15 2
84 33 2 23 3
85 12 3 17 0
86 25 2 28 1
87 28 2 24 5
88 17 1 10 3
89 1 1 18 1
90 0 4 28 0
91 18 5 17 1
92 5 4 7 3
93 27 1 21 1
94 11 2 5 4
95 30 2 8 0
96 4 1 7 5
97 16 0 23 3
98 27 1 15 2
99 21 3 11 4
100 15 2 28 1
101 23 2 35 0
102 30 3 35 1
103 19 0 26 0
104 30 1 14 0
105 19 5 1 4
106 5 5 15 0
107 16 4 0 2
108 29 3 23 0
109 26 3 13 3
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="800" font-family="sans-serif" font-size="10"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
innerRadius = 180,
outerRadius = Math.min(width, height) / 2.5,
g = svg.append("g").attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var xScaleOffset = Math.PI * 75/180;
var x = d3.scaleBand()
.range([xScaleOffset, 2 * Math.PI + xScaleOffset])
.align(0);
var y = d3.scaleLinear()
.range([innerRadius, outerRadius]);
var z = d3.scaleOrdinal()
.range(["#a1d76a", "#4d9221", "#91bfdb", "#4575b4"]);
var zClasses = ['внутренняя сторона', 'внутренняя сторона*', 'внешняя сторона', 'внешняя сторона*'];
d3.csv("coupled_stat.csv", function(d, i, columns) {
d.left_lane = (+d.left_lane_nonlethal) + (+d.left_lane_lethal);
d.right_lane = (+d.right_lane_nonlethal) + (+d.right_lane_lethal);
d.left_lane_nonlethal = +d.left_lane_nonlethal;
d.right_lane_nonlethal = -d.right_lane_nonlethal;
d.left_lane_lethal = +d.left_lane_lethal;
d.right_lane_lethal = -d.right_lane_lethal;
return d;
}, function(error, data) {
if (error) throw error;
x.domain(data.map(function(d) { return d.km; }));
y.domain([0, d3.max(data, function(d) { return d.left_lane; }) + d3.max(data, function(d) { return d.right_lane; })]);
z.domain(data.columns.slice(1));
// Accidents
g.append('g')
.selectAll("g")
.data(d3.stack().keys(data.columns.slice(1)).offset(stackOffsetOpposing)(data))
.enter().append("g")
.attr("fill", function(d) { return z(d.key); })
.selectAll("path")
.data(function(d) { return d; })
.enter().append("path")
.attr("d", d3.arc()
.innerRadius(function(d) { return y(d[0]); })
.outerRadius(function(d) { return y(d[1]); })
.startAngle(function(d) { return x(d.data.km); })
.endAngle(function(d) { return x(d.data.km) + x.bandwidth(); })
.padAngle(0.01)
.padRadius(innerRadius));
// Labels for xAxis
var label = g.append("g")
.selectAll("g")
.data(data)
.enter().append("g")
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "rotate(" + ((x(d.km) + x.bandwidth() / 2) * 180 / Math.PI - 90) + ")translate(" + y(0) + ",0)"; });
label.append("line")
.attr("x2", function(d) { return (((d.km % 5) == 0) | (d.km == '1')) ? -7 : -4 })
.attr("stroke", "#000");
label.append("text")
.attr("transform", function(d) { return (x(d.km) + x.bandwidth() / 2 + Math.PI / 2) % (2 * Math.PI) < Math.PI ? "rotate(90)translate(0,16)" : "rotate(-90)translate(0,-9)"; })
.text(function(d) {
var xlabel = (((d.km % 5) == 0) | (d.km == '1')) ? d.km : '';
return xlabel; });
//yAxis and Mean
var yAxis = g.append("g")
.attr("text-anchor", "middle");
// Max tick must match max y value!
var yTicksValues = d3.ticks(0, 80, 8);
var borderTick = yTicksValues.slice(-1)[0];
var yTick = yAxis
.selectAll("g")
.data(yTicksValues)
.enter().append("g");
yTick.append("circle")
.attr("fill", "none")
.attr("stroke", "#ccdcea")
.attr("r", y);
// Hallo
yTick.append("text")
.attr("y", function(d) { return -y(d); })
.attr("dy", "0.35em")
.attr("fill", "none")
.attr("stroke", "#fff")
.attr("stroke-width", 5)
.text(function(d, i) {
var format = y.tickFormat(5, "s")((d > borderTick/2) == true ? (borderTick - 10 * i) : 10*i);
return ((d == 0) | (d == borderTick)) ? '' : format;
});
// Text
yTick.append("text")
.attr("y", function(d) { return -y(d); })
.attr("dy", "0.35em")
.text(function(d, i) {
var format = y.tickFormat(5, "s")((d > borderTick/2) == true ? (borderTick - 10 * i) : 10*i);
return ((d == 0) | (d == borderTick)) ? '' : format;
});
yAxis.append("text")
.attr("y", function(d) { return -y(yTicksValues.pop()); })
.attr("dy", "-2em")
.text("МКАД, аварийность");
// Legend
var legend = g.append("g")
.selectAll("g")
.data(zClasses)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(-50," + (i - (zClasses.length - 1) / 2) * 25+ ")"; });
legend.append("circle")
.attr("r", 8)
.attr("fill", z);
legend.append("text")
.attr("x", 15)
.attr("y", 0)
.attr("dy", "0.35em")
.text(function(d) { return d; });
});
function stackOffsetOpposing(series, order) {
// Check if no staks (amount of series < 1)
if (!((n = series.length) > 1)) return;
// find max sum
var stackSums = [];
var stackMaxes = [];
for (var i = 0, n = series.length; i < n; i++) {
var stackMax = d3.max(series[i], function(d) { return Math.abs(d[1] - d[0])});
stackMaxes.push(stackMax);
}
var max = d3.sum(stackMaxes);
// Redifining baselines
for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
for (yp = 0, yn = max, i = 0; i < n; ++i) {
if ((dy = (d = series[order[i]][j])[1] - d[0]) >= 0) {
//d[0] -bottom; d[1] -top
d[0] = yp, d[1] = yp += dy;
} else if (dy < 0) {
d[1] = yn;
yn += dy;
d[0] = yn;
} else {
d[0] = yp;
}
}
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment