Skip to content

Instantly share code, notes, and snippets.

@angelicahl88
Created June 2, 2016 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save angelicahl88/3980ecd11ea53420a2844119a8833d23 to your computer and use it in GitHub Desktop.
Save angelicahl88/3980ecd11ea53420a2844119a8833d23 to your computer and use it in GitHub Desktop.
Ekokartan radar chart

Built with blockbuilder.org

This is an example of a radar chart used to visualise organic food purchases in Sweden. You can visit the full visualisation here.

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Lato:400,700' rel='stylesheet' type='text/css'>
<style>
body {
margin: 10px 0 0 0;
position:fixed;
top:0;
right:0;
bottom:0;
left:0;
background-color: #149EBA;
color: #fff;
font-family: 'Lato';
font-weight: 400;
}
#vkvArea {
position: relative;
width: 700px;
margin-left: auto;
margin-right: auto;
}
#vkvGraph {
text-transform: uppercase;
}
#vkvMainTitle {
font-weight: 700;
}
#sweVkv {
color: #dbd37e;
font-size: 20px;
margin: 0;
}
#prodResult {
position: absolute;
top: 10px;
right: 235px;
color: #6a213e;
font-weight: 700;
font-size: 24px;
}
#prodLegend {
position: absolute;
top: 0;
right: 50px;
color: rgba(255,255,255,0.6);
width: 220px;
text-align: right;
line-height: 24px;
}
#prodLegend span {
color: #6a213e;
}
text:hover {
cursor: pointer;
}
</style>
</head>
<body>
<div id="vkvArea">
<div id="vkvGraph">
<p id="vkvMainTitle">Vad köper vi?</p>
<p id="sweVkv">Sverige</p>
<div id="prodResult"></div>
<p id="prodLegend">Procent <span>ekologiskt</span> inköp per produktslag</p>
</div>
<div id="svgArea"></div>
</div>
<script>
d3.csv('vkv.csv', function(error, data) {
if (error) throw error;
function radarChart(data) {
var cfg = {
w: 280, //Width of the circle
h: 280, //Height of the circle
margin: {top: 50, right: 150, bottom: 100, left: 150 }, //The margins of the SVG
levels: 4, //How many levels or inner circles should there be drawn
maxValue: 1, //What is the value that the biggest circle will represent
labelFactor: 1.25, //How much farther than the radius of the outer circle should the labels be placed
wrapWidth: 60, //The number of pixels after which a label needs to be given a new line
opacityArea: 0.35, //The opacity of the area of the blob
dotRadius: 4, //The size of the colored circles of each blog
opacityCircles: 0.1, //The opacity of the circles of each blob
strokeWidth: 2, //The width of the stroke around each blob
roundStrokes: true //If true the area and stroke will follow a round path (cardinal-closed)
// color: '#6a213e' //Color
};
var allAxis = (data.map(function(i, j){ return i.Produktgrupp})); //Names of each axis
var total = allAxis.length; //The number of different axes
var radius = Math.min(cfg.w/2, cfg.h/2); //Radius of the outermost circle
var format = d3.format('%'); //Percentage formatting
var angleSlice = Math.PI * 2 / total; //The width in radians of each "slice"
//Scale for the radius
var rScale = d3.scale.linear()
.range([0, radius])
.domain([0, 1]);
// //Remove whatever chart with the same id/class was present before
// d3.select(id).select("svg").remove();
//Initiate the radar chart SVG
var svg = d3.select('#svgArea').append("svg")
.attr("width", cfg.w + cfg.margin.left + cfg.margin.right)
.attr("height", cfg.h + cfg.margin.top + cfg.margin.bottom)
.attr("class", "radar");
//Append a g element
var g = svg.append("g")
.attr('class', 'mainG')
.attr("transform", "translate(" + 300 + "," + 180 + ")");
//Wrapper for the grid & axes
var axisGrid = g.append("g").attr("class", "axisWrapper");
//Draw the background circles
axisGrid.selectAll('.levels')
.data(d3.range(1,(cfg.levels+1)).reverse())
.enter()
.append('circle')
.attr({
class: 'gridCirlcle',
r: function(d, i) {
return radius / cfg.levels * d;
}
})
.style({
fill: '#71C6D6',
stroke: 'rgba(255,255,255,0.4)',
'stroke-width': function(d, i) {
if (i > 0) {
return '1px';
} else {
return '0px';
}
},
'stroke-dasharray': function(d, i) {
if (i > 0) {
return '5,5';
}
}
});
//The radial line function
var radarLine = d3.svg.line.radial()
.interpolate("cardinal-closed")
.radius(function(d) { return rScale(d.Ekovarde); })
.angle(function(d,i) {return i * angleSlice; });
//Create a wrapper for the blobs
var blobWrapper = g.append("g")
.attr("class", "radarWrapper");
//Append the backgrounds
var blob = blobWrapper
.append('path')
.attr({
class:'radarArea',
d: radarLine(data)
})
.style({
fill: '#6a213e',
opacity: 0.6
});
//Create the outlines
blobWrapper.append('path')
.attr({
class: 'radarStroke',
d: function(d, i) {
return radarLine(data);
}
})
.style({
stroke: '#6a213e',
'stroke-width': '3px',
fill: 'none'
});
//Text indicating at what % each level is
var percentAxis = g.append("g").attr("class", "percentAxis");
percentAxis.selectAll('.axisPerc')
.data(d3.range(1,(cfg.levels+1)).reverse())
.enter().append('text')
.attr({
class: 'percentPerc',
x: 4,
y: function(d) {
return -d * radius / cfg.levels;
},
dy: '-0.5em',
dx: '-1.5em',
transform: 'rotate(25)'
})
.style({
'font-size': '10px',
fill: '#fff',
opacity: 1,
'font-family': 'Futura Heavy'
})
.text(function(d,i) {
if (d < 4) {
return format(1 * d/cfg.levels);
}
});
//Create the straight lines radiating outward from the center
var axis = axisGrid.selectAll(".axis")
.data(data)
.enter()
.append("g")
.attr("class", "axis");
function titleAlign(d, i) {
if (i == 0 || i == 8) {
return 'middle';
} else if (i > 0 && i < 8) {
return 'start';
} else if (i > 8) {
return 'end';
}
}
//Append the lines
axis.append('line')
.attr({
x1: 0,
y1: 0,
x2: function(d, i) {
return rScale(1.1) * Math.cos(angleSlice * i - Math.PI / 2);
},
y2: function(d, i) {
return rScale(1.1) * Math.sin(angleSlice * i- Math.PI / 2);
},
class: 'radialLine'
})
.style({
stroke: 'rgba(255,255,255,0.4)',
'stroke-width': '1px'
});
//Append the labels at each axis
axis.append('text')
.attr({
class: 'radialLegend',
'text-anchor': function(d,i) {
return titleAlign(d,i);
},
dy: '0.5em',
x: function(d, i) {
return rScale(1.2) * Math.cos(angleSlice * i - Math.PI / 2);
},
y: function(d, i) {
return rScale(1.2) * Math.sin(angleSlice * i - Math.PI / 2);
}
})
.style({
'font-size': '12px',
'opacity': 0.6,
'fill': '#fff'
})
.text(function(d) {
return d.Produktgrupp;
})
.on('mouseenter', function(d, i) {
d3.selectAll('path.sweden').style('opacity', 0);
d3.select(this).style({opacity: 1, 'font-weight': 700});
// display result for each project group
var ekovarde = d.Ekovarde;
d3.select('#prodResult').text(format(d.Ekovarde));
})
.on('mouseleave', function(d, i) {
d3.select(this).style({opacity: 0.6, 'font-weight': 400});
d3.select('#prodResult').text(''); //clear result text
});
}
radarChart(data);
}) //end load csv
</script>
</body>
Produktgrupp Ekovarde
Baljväxter & frö 0.567
Bröd 0.063
Cerealier 0.423
Drycker (alkoholfria) 0.087
Fisk & skaldjur 0.47
Frukt & bär 0.384
Färdigmat (hel & halvfabrikat) 0.105
Grönsaker och potatis 0.242
Kaffe & te 0.735
Kryddor 0.089
Kött &chark 0.136
Dressing, sås & vinäger 0.200
Matfett smörgås 0.306
Mejeriprodukter 0.489
Ägg 0.485
Övrigt 0.133
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment