Skip to content

Instantly share code, notes, and snippets.

@DIRKMJK DIRKMJK/.block
Last active Apr 6, 2019

Embed
What would you like to do?
Radial lollipop chart
height: 620
scrolling: no
license: mit

Radar charts have a drawback: there’s a suggestion that values are represented by the area within the line that connects data points. The radial lollipop chart solves that problem. Read the story behind the radial lollipop chart here.

var data = {"fiets": [{"location": "Ndsm-pont", "1980": 0.0, "2009": 1732.0}, {"location": "Buiksloterweg", "1980": 2207.0, "2009": 8142.0}, {"location": "Adelaarsweg", "1980": 689.0, "2009": 2979.0}, {"location": "Piet Heinkade", "1980": 492.0, "2009": 5742.0}, {"location": "IJtunnel", "1980": 0.0, "2009": 0.0}, {"location": "Mariniersplein", "1980": 281.0, "2009": 1572.0}, {"location": "Czaar Peterstraat", "1980": 239.0, "2009": 4189.0}, {"location": "Borneolaan", "1980": 0.0, "2009": 882.0}, {"location": "Cruquiuskade", "1980": 151.0, "2009": 2051.5355278143275}, {"location": "Zeeburgerpad", "1980": 302.0, "2009": 1239.0}, {"location": "Zeeburgerstr.", "1980": 2900.0, "2009": 5951.0}, {"location": "Alexanderplein", "1980": 4837.0, "2009": 9593.0}, {"location": "Krt. 's-Graves.str.", "1980": 1863.0, "2009": 4224.0}, {"location": "Spinozastraat", "1980": 374.0, "2009": 585.0}, {"location": "Weesperplein", "1980": 2597.0, "2009": 5953.0}, {"location": "Prof. Tulpplein", "1980": 3628.0, "2009": 8840.0}, {"location": "Oosteinde", "1980": 1322.0, "2009": 2764.0}, {"location": "Westeinde", "1980": 5093.0, "2009": 7282.0}, {"location": "Weteringlaan", "1980": 9514.0, "2009": 14956.0}, {"location": "Museumbrug", "1980": 11864.0, "2009": 12672.0}, {"location": "Max Euweplein", "1980": 0.0, "2009": 4600.0}, {"location": "Leidseplein", "1980": 6061.0, "2009": 9160.0}, {"location": "Nwe.Passeerdersstr.", "1980": 2741.0, "2009": 5097.858445317233}, {"location": "Elandsgracht", "1980": 6602.0, "2009": 11273.0}, {"location": "Rozengracht", "1980": 6405.0, "2009": 8450.0}, {"location": "2e Hugo de Grootstr.", "1980": 4586.0, "2009": 8117.0}, {"location": "Marnixplein", "1980": 2681.0, "2009": 4719.0}, {"location": "1e Marnixplants.", "1980": 1264.0, "2009": 2481.0}, {"location": "Haarlemmerplein", "1980": 3587.0, "2009": 10353.0}, {"location": "Van Diemenstraat", "1980": 833.0, "2009": 2903.681545472612}], "auto": [{"location": "Ndsm-pont", "1980": 0.0, "2009": 0.0}, {"location": "Buiksloterweg", "1980": 0.0, "2009": 0.0}, {"location": "Adelaarsweg", "1980": 215.0, "2009": 0.0}, {"location": "Piet Heinkade", "1980": 9874.0, "2009": 13816.0}, {"location": "IJtunnel", "1980": 40717.0, "2009": 26991.0}, {"location": "Mariniersplein", "1980": 7940.0, "2009": 7199.0}, {"location": "Czaar Peterstraat", "1980": 3094.0, "2009": 0.0}, {"location": "Borneolaan", "1980": 0.0, "2009": 3998.0}, {"location": "Cruquiuskade", "1980": 3711.0, "2009": 2922.0}, {"location": "Zeeburgerpad", "1980": 1353.0, "2009": 777.0}, {"location": "Zeeburgerstr.", "1980": 13093.0, "2009": 7009.0}, {"location": "Alexanderplein", "1980": 6068.0, "2009": 3748.0}, {"location": "Krt. 's-Graves.str.", "1980": 7744.0, "2009": 2440.0}, {"location": "Spinozastraat", "1980": 0.0, "2009": 0.0}, {"location": "Weesperplein", "1980": 26256.0, "2009": 21160.0}, {"location": "Prof. Tulpplein", "1980": 0.0, "2009": 2.0}, {"location": "Oosteinde", "1980": 3316.0, "2009": 1202.0}, {"location": "Westeinde", "1980": 16434.0, "2009": 7076.0}, {"location": "Weteringlaan", "1980": 12999.0, "2009": 6506.0}, {"location": "Museumbrug", "1980": 7148.0, "2009": 3246.0}, {"location": "Max Euweplein", "1980": 0.0, "2009": 7.0}, {"location": "Leidseplein", "1980": 6360.0, "2009": 3775.084095992781}, {"location": "Nwe.Passeerdersstr.", "1980": 3509.0, "2009": 1474.7951658918582}, {"location": "Elandsgracht", "1980": 7806.0, "2009": 4685.0}, {"location": "Rozengracht", "1980": 13929.0, "2009": 8119.0}, {"location": "2e Hugo de Grootstr.", "1980": 7920.0, "2009": 4385.0}, {"location": "Marnixplein", "1980": 6792.0, "2009": 3158.0}, {"location": "1e Marnixplants.", "1980": 90.0, "2009": 0.0}, {"location": "Haarlemmerplein", "1980": 16060.0, "2009": 9804.287365883474}, {"location": "Van Diemenstraat", "1980": 14940.0, "2009": 12076.214029503493}]};
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Radial lollipop chart</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://d3js.org/d3.v4.0.0-rc.2.min.js"></script>
<script src="data.js"></script>
</head>
<body>
<div id="chart"></div>
</body>
<script>
// settings
var max = 15000;
var subset = 'fiets';
var ticks = 5;
var rotate = -1;
data = data[subset];
var margin = {top: 50, right: 50, bottom: 50, left: 50},
width = 500,
height = 500;
var radius = 200;
var svg = d3.select('#chart').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 + ')');
var center_x = height / 2;
var center_y = width / 2;
function rotated(i){
var rotated_i = parseInt(i) + rotate;
if(rotated_i >= data.length){
rotated_i = i - data.length;
}
else if(rotated_i < 0) {
rotated_i = data.length - 1 + parseInt(i);
}
return rotated_i
}
function to_radian(i){
return i * 2 * Math.PI / data.length;
}
function get_xy(value, index){
var length = radius * value / max;
y = center_y - length * Math.cos(to_radian(rotated(index)));
x = center_x + length * Math.sin(to_radian(rotated(index)));
return [x, y];
}
function get_anchor(i){
if(rotated(i) == 0 | rotated(i) == data.length / 2){
return 'middle';
}
else if(rotated(i) < data.length / 2){
return 'start';
}
else{
return 'end';
}
}
function get_dy(index){
var dy = -3 * Math.cos(to_radian(rotated(index)));
dy += 3;
if(rotated(index) == 0){
dy -= 4;
}
return dy;
}
for(tick = 1; tick <= ticks; tick++) {
var value = max * tick / ticks;
var plabel = get_xy(value, 1);
console.log(value, plabel)
svg.append('text')
.attr('x', plabel[0])
.attr('y', plabel[1])
.attr('dx', 2)
.attr('class', 'label')
.text(value);
}
for(i in data){
var item = data[i];
for(tick = 1; tick <= ticks; tick++){
var value = max * tick / ticks;
var start = get_xy(value, i);
var end = get_xy(value, parseInt(i) + 1);
svg.append('line')
.attr('x1', start[0])
.attr('y1', start[1])
.attr('x2', end[0])
.attr('y2', end[1])
.style('stroke', 'grey')
.style('stroke-width', 0.5);
}
var p1980 = get_xy(item[1980], i);
var p2009 = get_xy(item[2009], i);
var end = get_xy(max, i);
svg.append('line')
.attr('x1', center_x)
.attr('y1', center_y)
.attr('x2', end[0])
.attr('y2', end[1])
.style('stroke', 'grey')
.style('stroke-width', 0.5);
var highest_value = Math.max(item[1980], item[2009]);
var lowest_value = Math.min(item[1980], item[2009]);
if(lowest_value > max){
start = get_xy(max, i);
end = get_xy(highest_value, i);
svg.append('line')
.attr('x1', start[0])
.attr('y1', start[1])
.attr('x2', end[0])
.attr('y2', end[1])
.style('stroke', 'grey')
.style('stroke-width', 0.5)
.style("stroke-dasharray", ("3, 3"));
}
svg.append('line')
.attr('x1', p1980[0])
.attr('y1', p1980[1])
.attr('x2', p2009[0])
.attr('y2', p2009[1])
.style('stroke', 'black')
.style('stroke-width', 1.3);
svg.append('circle')
.attr('cx', p2009[0])
.attr('cy', p2009[1])
.attr('r', '3')
.attr('fill', 'red')
var plabel = get_xy(max * 1.04, i);
svg.append('text')
.attr('x', plabel[0])
.attr('y', plabel[1])
.attr('dy', function(){return get_dy(i)})
.attr('text-anchor', get_anchor(i))
.attr('class', 'label')
.text(item.location)
}
</script>
.label {
font-family: sans-serif;
font-size: 8px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.