An example of a stylized scatter plot with re-usable code organization using D3 v4.
Last active
August 3, 2017 13:31
-
-
Save curran/298c130e67b40ed84f8c919e748d2e72 to your computer and use it in GitHub Desktop.
Scatter Plot with Color Legend
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit | |
border: yes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Solution</title> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { | |
margin: 0px; | |
} | |
.axis .tick line { | |
stroke-width: 2px; | |
stroke: #dddddd; | |
} | |
.axis .tick text { | |
font-size: 30px; | |
fill: #8E8883; | |
} | |
.axis .domain { | |
display: none; | |
} | |
.axis__label { | |
text-anchor: middle; | |
font-size: 50px; | |
fill: #635F5D; | |
} | |
.legend .tick text { | |
font-size: 30px; | |
fill: #8E8883; | |
font-family: sans-serif; | |
alignment-baseline: middle; | |
} | |
.legend__label { | |
font-size: 45px; | |
fill: #635F5D; | |
font-family: sans-serif; | |
} | |
</style> | |
</head> | |
<body> | |
<svg width="960" height="500"></svg> | |
<script> | |
const xValue = d => d.sepalLength; | |
const yValue = d => d.petalLength; | |
const colorValue = d => d.species; | |
const xLabel = "Sepal Length"; | |
const yLabel = "Petal Length"; | |
const margin = {top: 30, right: 300, bottom: 100, left: 100}; | |
const svg = d3.select("svg"); | |
const width = +svg.attr("width"); | |
const height = +svg.attr("height"); | |
const innerWidth = width - margin.left - margin.right; | |
const innerHeight = height - margin.top - margin.bottom; | |
const xScale = d3.scaleLinear().range([0, innerWidth]); | |
const yScale = d3.scaleLinear().range([innerHeight, 0]); | |
const colorScale = d3.scaleOrdinal() | |
.range(["#eb8e37", "#1ac6cf", "#e35dd4"]); | |
const xAxis = d3.axisBottom() | |
.scale(xScale) | |
.tickSizeInner(-innerHeight) | |
.tickPadding(15); | |
const yAxis = d3.axisLeft() | |
.scale(yScale) | |
.tickSizeInner(-innerWidth) | |
.ticks(5) | |
.tickPadding(10); | |
const g = svg.append("g") | |
.attr("transform", `translate(${margin.left}, ${margin.top})`); | |
const xAxisG = g.append("g") | |
.attr("class", "axis") | |
.attr("transform", `translate(0, ${innerHeight})`); | |
const yAxisG = g.append("g") | |
.attr("class", "axis"); | |
xAxisG | |
.append("text") | |
.attr("class", "axis__label") | |
.attr("x", innerWidth / 2) | |
.attr("y", 85) | |
.text(xLabel); | |
yAxisG | |
.append("text") | |
.attr("class", "axis__label") | |
.attr("transform", "rotate(-90)") | |
.attr("x", -innerHeight / 2) | |
.attr("y", -45) | |
.text(yLabel); | |
function colorLegend(selection, props){ | |
const colorScale = props.colorScale; | |
const positionX = props.positionX; | |
const positionY = props.positionY; | |
const tickRadius = props.tickRadius; | |
const tickSpacing = props.tickSpacing; | |
const tickPadding = props.tickPadding; | |
const label = props.label; | |
const labelX = props.labelX; | |
const labelY = props.labelY; | |
let legendG = selection | |
.selectAll(".legend--color") | |
.data([null]); | |
legendG = legendG | |
.enter().append("g") | |
.attr("class", "legend legend--color") | |
.merge(legendG) | |
.attr("transform", `translate(${positionX}, ${positionY})`); | |
const legendLabel = legendG | |
.selectAll(".legend__label") | |
.data([null]); | |
legendLabel | |
.enter().append("text") | |
.attr("class", "legend__label") | |
.merge(legendLabel) | |
.attr("x", labelX) | |
.attr("y", labelY) | |
.text(label); | |
const ticks = legendG | |
.selectAll(".tick") | |
.data(colorScale.domain()); | |
const ticksEnter = ticks | |
.enter().append("g") | |
.attr("class", "tick"); | |
ticksEnter | |
.merge(ticks) | |
.attr("transform", (d, i) => `translate(0, ${i * tickSpacing})`); | |
ticks.exit().remove(); | |
ticksEnter | |
.append("circle") | |
.merge(ticks.select("circle")) | |
.attr("r", tickRadius) | |
.attr("fill", colorScale); | |
ticksEnter | |
.append("text") | |
.merge(ticks.select("text")) | |
.attr("x", tickRadius + tickPadding) | |
.text(d => d); | |
} | |
function render(data){ | |
xScale | |
.domain(d3.extent(data, xValue)) | |
.nice(); | |
yScale | |
.domain(d3.extent(data, yValue)) | |
.nice(); | |
colorScale | |
.domain(d3.set(data.map(colorValue)).values().sort()); | |
xAxisG.call(xAxis); | |
yAxisG.call(yAxis); | |
const circles = g.selectAll("circle").data(data); | |
circles.exit().remove(); | |
circles | |
.enter().append("circle") | |
.attr("r", 5) | |
.merge(circles) | |
.attr("cx", d => xScale(xValue(d))) | |
.attr("cy", d => yScale(yValue(d))) | |
.attr("fill", d => colorScale(colorValue(d))); | |
svg.call(colorLegend, { | |
colorScale: colorScale, | |
positionX: 750, | |
positionY: 200, | |
tickRadius: 12, | |
tickSpacing: 35, | |
tickPadding: 6, | |
label: "Species", | |
labelX: -20, | |
labelY: -30 | |
}); | |
} | |
function type(d){ | |
d.sepalLength = +d.sepalLength; | |
d.sepalWidth = +d.sepalWidth; | |
d.petalLength = +d.petalLength; | |
d.petalWidth = +d.petalWidth; | |
return d; | |
} | |
d3.csv("iris.csv", type, render); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
sepalLength | sepalWidth | petalLength | petalWidth | species | |
---|---|---|---|---|---|
5.1 | 3.5 | 1.4 | 0.2 | setosa | |
4.9 | 3.0 | 1.4 | 0.2 | setosa | |
4.7 | 3.2 | 1.3 | 0.2 | setosa | |
4.6 | 3.1 | 1.5 | 0.2 | setosa | |
5.0 | 3.6 | 1.4 | 0.2 | setosa | |
5.4 | 3.9 | 1.7 | 0.4 | setosa | |
4.6 | 3.4 | 1.4 | 0.3 | setosa | |
5.0 | 3.4 | 1.5 | 0.2 | setosa | |
4.4 | 2.9 | 1.4 | 0.2 | setosa | |
4.9 | 3.1 | 1.5 | 0.1 | setosa | |
5.4 | 3.7 | 1.5 | 0.2 | setosa | |
4.8 | 3.4 | 1.6 | 0.2 | setosa | |
4.8 | 3.0 | 1.4 | 0.1 | setosa | |
4.3 | 3.0 | 1.1 | 0.1 | setosa | |
5.8 | 4.0 | 1.2 | 0.2 | setosa | |
5.7 | 4.4 | 1.5 | 0.4 | setosa | |
5.4 | 3.9 | 1.3 | 0.4 | setosa | |
5.1 | 3.5 | 1.4 | 0.3 | setosa | |
5.7 | 3.8 | 1.7 | 0.3 | setosa | |
5.1 | 3.8 | 1.5 | 0.3 | setosa | |
5.4 | 3.4 | 1.7 | 0.2 | setosa | |
5.1 | 3.7 | 1.5 | 0.4 | setosa | |
4.6 | 3.6 | 1.0 | 0.2 | setosa | |
5.1 | 3.3 | 1.7 | 0.5 | setosa | |
4.8 | 3.4 | 1.9 | 0.2 | setosa | |
5.0 | 3.0 | 1.6 | 0.2 | setosa | |
5.0 | 3.4 | 1.6 | 0.4 | setosa | |
5.2 | 3.5 | 1.5 | 0.2 | setosa | |
5.2 | 3.4 | 1.4 | 0.2 | setosa | |
4.7 | 3.2 | 1.6 | 0.2 | setosa | |
4.8 | 3.1 | 1.6 | 0.2 | setosa | |
5.4 | 3.4 | 1.5 | 0.4 | setosa | |
5.2 | 4.1 | 1.5 | 0.1 | setosa | |
5.5 | 4.2 | 1.4 | 0.2 | setosa | |
4.9 | 3.1 | 1.5 | 0.1 | setosa | |
5.0 | 3.2 | 1.2 | 0.2 | setosa | |
5.5 | 3.5 | 1.3 | 0.2 | setosa | |
4.9 | 3.1 | 1.5 | 0.1 | setosa | |
4.4 | 3.0 | 1.3 | 0.2 | setosa | |
5.1 | 3.4 | 1.5 | 0.2 | setosa | |
5.0 | 3.5 | 1.3 | 0.3 | setosa | |
4.5 | 2.3 | 1.3 | 0.3 | setosa | |
4.4 | 3.2 | 1.3 | 0.2 | setosa | |
5.0 | 3.5 | 1.6 | 0.6 | setosa | |
5.1 | 3.8 | 1.9 | 0.4 | setosa | |
4.8 | 3.0 | 1.4 | 0.3 | setosa | |
5.1 | 3.8 | 1.6 | 0.2 | setosa | |
4.6 | 3.2 | 1.4 | 0.2 | setosa | |
5.3 | 3.7 | 1.5 | 0.2 | setosa | |
5.0 | 3.3 | 1.4 | 0.2 | setosa | |
7.0 | 3.2 | 4.7 | 1.4 | versicolor | |
6.4 | 3.2 | 4.5 | 1.5 | versicolor | |
6.9 | 3.1 | 4.9 | 1.5 | versicolor | |
5.5 | 2.3 | 4.0 | 1.3 | versicolor | |
6.5 | 2.8 | 4.6 | 1.5 | versicolor | |
5.7 | 2.8 | 4.5 | 1.3 | versicolor | |
6.3 | 3.3 | 4.7 | 1.6 | versicolor | |
4.9 | 2.4 | 3.3 | 1.0 | versicolor | |
6.6 | 2.9 | 4.6 | 1.3 | versicolor | |
5.2 | 2.7 | 3.9 | 1.4 | versicolor | |
5.0 | 2.0 | 3.5 | 1.0 | versicolor | |
5.9 | 3.0 | 4.2 | 1.5 | versicolor | |
6.0 | 2.2 | 4.0 | 1.0 | versicolor | |
6.1 | 2.9 | 4.7 | 1.4 | versicolor | |
5.6 | 2.9 | 3.6 | 1.3 | versicolor | |
6.7 | 3.1 | 4.4 | 1.4 | versicolor | |
5.6 | 3.0 | 4.5 | 1.5 | versicolor | |
5.8 | 2.7 | 4.1 | 1.0 | versicolor | |
6.2 | 2.2 | 4.5 | 1.5 | versicolor | |
5.6 | 2.5 | 3.9 | 1.1 | versicolor | |
5.9 | 3.2 | 4.8 | 1.8 | versicolor | |
6.1 | 2.8 | 4.0 | 1.3 | versicolor | |
6.3 | 2.5 | 4.9 | 1.5 | versicolor | |
6.1 | 2.8 | 4.7 | 1.2 | versicolor | |
6.4 | 2.9 | 4.3 | 1.3 | versicolor | |
6.6 | 3.0 | 4.4 | 1.4 | versicolor | |
6.8 | 2.8 | 4.8 | 1.4 | versicolor | |
6.7 | 3.0 | 5.0 | 1.7 | versicolor | |
6.0 | 2.9 | 4.5 | 1.5 | versicolor | |
5.7 | 2.6 | 3.5 | 1.0 | versicolor | |
5.5 | 2.4 | 3.8 | 1.1 | versicolor | |
5.5 | 2.4 | 3.7 | 1.0 | versicolor | |
5.8 | 2.7 | 3.9 | 1.2 | versicolor | |
6.0 | 2.7 | 5.1 | 1.6 | versicolor | |
5.4 | 3.0 | 4.5 | 1.5 | versicolor | |
6.0 | 3.4 | 4.5 | 1.6 | versicolor | |
6.7 | 3.1 | 4.7 | 1.5 | versicolor | |
6.3 | 2.3 | 4.4 | 1.3 | versicolor | |
5.6 | 3.0 | 4.1 | 1.3 | versicolor | |
5.5 | 2.5 | 4.0 | 1.3 | versicolor | |
5.5 | 2.6 | 4.4 | 1.2 | versicolor | |
6.1 | 3.0 | 4.6 | 1.4 | versicolor | |
5.8 | 2.6 | 4.0 | 1.2 | versicolor | |
5.0 | 2.3 | 3.3 | 1.0 | versicolor | |
5.6 | 2.7 | 4.2 | 1.3 | versicolor | |
5.7 | 3.0 | 4.2 | 1.2 | versicolor | |
5.7 | 2.9 | 4.2 | 1.3 | versicolor | |
6.2 | 2.9 | 4.3 | 1.3 | versicolor | |
5.1 | 2.5 | 3.0 | 1.1 | versicolor | |
5.7 | 2.8 | 4.1 | 1.3 | versicolor | |
6.3 | 3.3 | 6.0 | 2.5 | virginica | |
5.8 | 2.7 | 5.1 | 1.9 | virginica | |
7.1 | 3.0 | 5.9 | 2.1 | virginica | |
6.3 | 2.9 | 5.6 | 1.8 | virginica | |
6.5 | 3.0 | 5.8 | 2.2 | virginica | |
7.6 | 3.0 | 6.6 | 2.1 | virginica | |
4.9 | 2.5 | 4.5 | 1.7 | virginica | |
7.3 | 2.9 | 6.3 | 1.8 | virginica | |
6.7 | 2.5 | 5.8 | 1.8 | virginica | |
7.2 | 3.6 | 6.1 | 2.5 | virginica | |
6.5 | 3.2 | 5.1 | 2.0 | virginica | |
6.4 | 2.7 | 5.3 | 1.9 | virginica | |
6.8 | 3.0 | 5.5 | 2.1 | virginica | |
5.7 | 2.5 | 5.0 | 2.0 | virginica | |
5.8 | 2.8 | 5.1 | 2.4 | virginica | |
6.4 | 3.2 | 5.3 | 2.3 | virginica | |
6.5 | 3.0 | 5.5 | 1.8 | virginica | |
7.7 | 3.8 | 6.7 | 2.2 | virginica | |
7.7 | 2.6 | 6.9 | 2.3 | virginica | |
6.0 | 2.2 | 5.0 | 1.5 | virginica | |
6.9 | 3.2 | 5.7 | 2.3 | virginica | |
5.6 | 2.8 | 4.9 | 2.0 | virginica | |
7.7 | 2.8 | 6.7 | 2.0 | virginica | |
6.3 | 2.7 | 4.9 | 1.8 | virginica | |
6.7 | 3.3 | 5.7 | 2.1 | virginica | |
7.2 | 3.2 | 6.0 | 1.8 | virginica | |
6.2 | 2.8 | 4.8 | 1.8 | virginica | |
6.1 | 3.0 | 4.9 | 1.8 | virginica | |
6.4 | 2.8 | 5.6 | 2.1 | virginica | |
7.2 | 3.0 | 5.8 | 1.6 | virginica | |
7.4 | 2.8 | 6.1 | 1.9 | virginica | |
7.9 | 3.8 | 6.4 | 2.0 | virginica | |
6.4 | 2.8 | 5.6 | 2.2 | virginica | |
6.3 | 2.8 | 5.1 | 1.5 | virginica | |
6.1 | 2.6 | 5.6 | 1.4 | virginica | |
7.7 | 3.0 | 6.1 | 2.3 | virginica | |
6.3 | 3.4 | 5.6 | 2.4 | virginica | |
6.4 | 3.1 | 5.5 | 1.8 | virginica | |
6.0 | 3.0 | 4.8 | 1.8 | virginica | |
6.9 | 3.1 | 5.4 | 2.1 | virginica | |
6.7 | 3.1 | 5.6 | 2.4 | virginica | |
6.9 | 3.1 | 5.1 | 2.3 | virginica | |
5.8 | 2.7 | 5.1 | 1.9 | virginica | |
6.8 | 3.2 | 5.9 | 2.3 | virginica | |
6.7 | 3.3 | 5.7 | 2.5 | virginica | |
6.7 | 3.0 | 5.2 | 2.3 | virginica | |
6.3 | 2.5 | 5.0 | 1.9 | virginica | |
6.5 | 3.0 | 5.2 | 2.0 | virginica | |
6.2 | 3.4 | 5.4 | 2.3 | virginica | |
5.9 | 3.0 | 5.1 | 1.8 | virginica |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
�PNG | |