Skip to content

Instantly share code, notes, and snippets.

@pmbrull
Last active November 1, 2018 22:03
Show Gist options
  • Save pmbrull/6819e88b4eb07cce46a0e1d2ef25cd99 to your computer and use it in GitHub Desktop.
Save pmbrull/6819e88b4eb07cce46a0e1d2ef25cd99 to your computer and use it in GitHub Desktop.
Mini Project from Udacity's Data Visualization and D3.js

A Visualization Makeover

Mini Project from Udacity's Data Visualization and D3.js

The aim of this project is finding a graphic that does not fit into visualization's best practices, which can either make the viewer get mistaken information from it or difficult the information ingestion process. Therefore, we will get a graphic which we think can be improved, discuss the aspects that we feel were treated poorly and propose a better solution.

The chosen visualization is trying to help the reader compare how much time different countries guarantee of paternity leave. It was extracted from WTF Visualizations:

WTF-Viz

However, there are quite a few issues going on:

  • The choice of a pie chart is fairly useless, as the divisions have no real meaning despite of the country they are referring to. At most, you could say from it that around ~41% of countries guarantee 2 weeks of paternity leave, but as this sample of 12 countries is rather random it is hard for me to figure out how much useful this information actually is.
  • It is lacking category separation and label positioning can be confusing.
  • As if anyone could be surprised, Unitated States stands at the center.
  • The real information, amount of time, is shown in the pieces length. However, all the steps measure the same and do not represent the real data change. For example, they represent as equal the change from 2 weeks to 15 days than the 20 days to 54.
  • Data is not normalized: days, weeks and months.
  • Color change gives no additional information, as it only separates time categories.
  • I also find the subtitle choice somehow off and useless.

Proposal

An improved visualization could be a bar chart, where each category represents a country and amounts are normalized. Also, if we wanted to focus the comparison against the US, we could use the same color for all countries and a different one for the United States. However, an amount of 0 can't be colorized. We will keep it simple, with no Y axis and showing the amount directly on the bars. Keeping a graphic simple and focusing all the visual effects on presenting the information makes the resulting visualization easier to digest and helps the reader focus on what is important.

Result

Obtained this static graphic with d3.js, css in separated file. All feedback is welcome :)

result

You can run it downloading all files in a given directory and calling python -m http.server, using python3.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<!-- load local CSS -->
<link rel="stylesheet" href="style.css">
<script type="text/javascript">
function draw(data) {
const d = data['content']
.sort((a, b) => b.time - a.time) // decreasing
.map(({country, time}) => ({name: country, value: time}))
var margin = 75,
width = 800 - 2 * margin,
height = 600 - 2 * margin;
const x = d3.scaleBand()
.range([0, width])
.domain(d.map(s => s.name))
.padding(0.4);
const y = d3.scaleLinear()
.range([height, 0])
.domain([0, d3.max(d, function(s){return s.value;})])
.nice();
xAxis = g => g
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x)
.tickSizeOuter(0))
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin)
.attr("height", height + margin)
.attr('transform', `translate(${margin / 2}, ${margin / 2})`)
.append('g')
.attr('class','chart');
const barGroups = svg.selectAll()
.data(d)
.enter()
.append("g")
barGroups
.append('rect')
.attr('class', 'bar')
.attr("x", s => x(s.name))
.attr("y", s => y(s.value))
.attr("height", d => y(0) - y(d.value))
.attr("width", x.bandwidth());
barGroups
.append('text')
.attr('class', 'value')
.attr('x', s => x(s.name) + x.bandwidth() / 2)
.attr('y', s => y(s.value) + 20)
// only add text for values greater than 0
.text(s => {return s.value !== 0 ? `${s.value}` : '' })
// X-Axis
svg
.append("g")
.attr('class', 'axis')
.call(xAxis)
.selectAll("text")
.attr('class', 'xtick-label')
//.attr("dx", "-.8em")
//.attr("dy", ".15em")
.attr("transform", "rotate(30)");
// Title
svg
.append('text')
.attr('class', 'title')
.attr('x', width / 2)
.attr('y', 20)
.text('Paid Paternity Leave')
// Y-Label
svg
.append('text')
.attr('class', 'label')
.attr('x', -(height / 2))
.attr('y', margin / 2 - 25)
.attr('transform', 'rotate(-90)')
.text('Time in days')
// X-Label
svg
.append('text')
.attr('class', 'label')
.attr('x', width / 2)
.attr('y', height + 60)
.text('Countries')
};
</script>
</head>
<body>
<script type="text/javascript">
/*
Use D3 to load json file and pass
the contents to the draw function.
Applied d3 V5 load changes
*/
d3.json("paternity-leave.json")
.then(draw);
</script>
</body>
</html>
{
"name": "Paternity leave guaranteed time in days",
"content": [
{
"country": "United States",
"time": 0
},
{
"country": "Bahamas",
"time": 7
},
{
"country": "Singapore",
"time": 7
},
{
"country": "UK",
"time": 14
},
{
"country": "Denmark",
"time": 14
},
{
"country": "Australia",
"time": 14
},
{
"country": "Venezuela",
"time": 14
},
{
"country": "Kenya",
"time": 14
},
{
"country": "Spain",
"time": 15
},
{
"country": "Portugal",
"time": 20
},
{
"country": "Finland",
"time": 54
},
{
"country": "Iceland",
"time": 90
}
]
}
body {
font-family: 'Open Sans', sans-serif;
}
path {
stroke: #607d8b;
}
line {
stroke: #607d8b;
}
.bar {
fill: #4fc3f7;
}
text.value {
font-size: 12px;
text-anchor: middle;
fill: white;
}
text.label {
font-size: 14px;
text-anchor: middle;
fill: #37474f;
}
text.xtick-label {
text-anchor: start;
fill: #37474f;
}
text.title {
font-size: 22px;
font-weight: 600;
text-anchor: middle;
fill: #263238;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment