This is an interactive scatterplot written with d3.js v5 and based on the example from Interactive Data Visualization for the Web.
Data Source: Rounak Banik
This is an interactive scatterplot written with d3.js v5 and based on the example from Interactive Data Visualization for the Web.
Data Source: Rounak Banik
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<style> | |
.text { | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
.label { | |
font-family: Helvetica; | |
font-size: 12px; | |
} | |
h1 { | |
position: absolute; | |
left: 70px; | |
} | |
p { | |
position: absolute; | |
left: 70px; | |
top: 70px; | |
} | |
</style> | |
<title> Pokemon data visualization</title> | |
<script type="text/javascript" src="https://d3js.org/d3.v5.min.js"></script> | |
<link rel="stylesheet" href="style.css"> | |
</head> | |
<body> | |
<h1>800 Pokemon's Attack V.S. Defense</h1> | |
<p> | |
<input type='radio' name='filterPreset' value='all' checked='true'> All | |
<input type='radio' name='filterPreset' value='non-legendary'> Non-Legendary | |
<input type='radio' name='filterPreset' value='legendary'> Legendary | |
</p> | |
<script type="text/javascript"> | |
var rowConverter = function(d) { | |
return { | |
name: d.name, | |
atk: parseFloat(d['atk']), | |
def: parseFloat(d['def']), | |
isLegend: parseFloat(d['is_legendary']) | |
}; | |
}; | |
//read csv | |
d3.csv("https://raw.githubusercontent.com/sabrinamochi/pokemon/master/df_scatter.csv", rowConverter).then(function(data) { | |
var dataset = data; | |
console.table(dataset, ['name', 'atk', 'def', 'isLegend']); | |
// set the width, height and padding | |
var w = 1000; | |
var h = 400; | |
var padding = 20; | |
// create scales and axises | |
var xScale = d3.scaleLinear() | |
.domain([0, d3.max(dataset, function(d) { | |
return d.atk; | |
})]) | |
.range([padding * 4, w - padding * 4]); | |
var yScale = d3.scaleLinear() | |
.domain([0, d3.max(dataset, function(d) { | |
return d.def; | |
})]) | |
.range([h - padding * 2, padding * 2]); | |
var xAxis = d3.axisBottom() | |
.scale(xScale) | |
.ticks(5); | |
var yAxis = d3.axisLeft() | |
.scale(yScale) | |
.ticks(5); | |
var svg = d3.select('body') | |
.append('g') | |
.append('svg') | |
.attr('transform', 'translate(0,' + padding * 6 + ')') | |
.attr('width', w) | |
.attr('height', h); | |
var bubble = svg.append('g') | |
.attr('transform', 'translate(0,' + (0 - padding * 1 / 100) + ')') | |
.selectAll('circle') | |
.data(dataset) | |
.enter() | |
.append('circle') | |
.attr('cx', function(d) { | |
return xScale(d.atk); | |
}) | |
.attr('cy', function(d) { | |
return yScale(d.def); | |
}) | |
.attr('r', 3) | |
.attr('fill', function(d) { | |
if (+d.isLegend == 1) { | |
return '#FA8072'; | |
} else { | |
return '#41B5C1 '; | |
} | |
}); | |
var text = svg.selectAll('text') | |
.data(dataset) | |
.enter() | |
.append('text') | |
.attr('class', 'text') | |
.text(function(d) { | |
if (+d.atk >= 160 || +d.def >= 180) { | |
return d.name; | |
} | |
}) | |
.attr('x', function(d) { | |
return xScale(d.atk); | |
}) | |
.attr('y', function(d) { | |
return yScale(d.def) + 15; | |
}) | |
.attr('fill', function(d) { | |
if (+d.isLegend == 1) { | |
return '#FA8072'; | |
} else { | |
return '#41B5C1 '; | |
} | |
}); | |
svg.append('g') | |
.attr('transform', 'translate(0,' + (h - padding * 2) + ')') | |
.call(xAxis); | |
svg.append('g') | |
.attr('transform', 'translate(' + padding * 4 + ',' + (0 - padding * 1 / 100) + ')') | |
.call(yAxis); | |
svg.append('g') | |
.attr('class', 'label') | |
.append('text') | |
.attr('transform', 'translate(' + w / 2 + ',' + (h - padding * 1 / 100) + ')') | |
.style('text-anchor', 'middle') | |
.text('Attack') | |
svg.append('g') | |
.attr('class', 'label') | |
.append('text') | |
.attr('transform', 'translate(' + (padding + 10) + ',' + (h / 2) + ')rotate(-90)') | |
.style('text-anchor', 'middle') | |
.text('Defense') | |
d3.selectAll('input') | |
.on('click', function() { | |
var view = d3.select(this).node().value; | |
// reset all to invisible | |
bubble.attr('fill', 'none'); | |
switch (view) { | |
case 'all': | |
bubble.attr('fill', function(d) { | |
if (+d.isLegend == 1) { | |
return '#FA8072'; | |
} else { | |
return '#41B5C1 '; | |
} | |
}); | |
text.text(function(d) { | |
if (+d.atk >= 160 || +d.def >= 180) { | |
return d.name; | |
} | |
}) | |
.attr('x', function(d) { | |
return xScale(d.atk); | |
}) | |
.attr('y', function(d) { | |
return yScale(d.def) + 15; | |
}) | |
.attr('fill', function(d) { | |
if (+d.isLegend == 1) { | |
return '#FA8072'; | |
} else { | |
return '#41B5C1 '; | |
} | |
}); | |
break; | |
case 'non-legendary': | |
bubble.attr('fill', function(d) { | |
if (+d.isLegend == 0) { | |
return '#41B5C1 '; | |
} else { | |
return 'none'; | |
}; | |
}); | |
text.text(function(d) { | |
if (+d.isLegend == 1) { | |
return ' '; | |
} else if (+d.atk >= 160 || +d.def >= 180) { | |
return d.name; | |
} | |
}) | |
break; | |
case 'legendary': | |
bubble.attr('fill', function(d) { | |
if (+d.isLegend == 1) { | |
return '#FA8072'; | |
} else { | |
return 'none'; | |
}; | |
}); | |
text.text(function(d) { | |
if (+d.isLegend == 0) { | |
return ' '; | |
} else if (+d.atk >= 160 || +d.def >= 180) { | |
return d.name; | |
} | |
}) | |
break; | |
} | |
}); | |
}); | |
</script> | |
</body> | |
</html> |