Published
Edited
Apr 20, 2020
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// https://www.kaggle.com/mirichoi0218/insurance
data = {
const csv = await FileAttachment("insurance.csv").text();
return d3.csvParse(csv);
}
Insert cell
// Body Mass Index (Session 1)
x_variable = "bmi"
Insert cell
// Insomnia Severity Index
y_variable = "charges"
Insert cell
// Young: 20-30, Old: 65-75
color_variable = "region"
Insert cell
title = "Insurance Costs"
Insert cell
chart_data = {
const arr = [];

data.map(d => {
if (!isNaN(d[x_variable]) && !isNaN(d[y_variable])) {
arr.push({
x: parseFloat(d[x_variable]),
y: parseFloat(d[y_variable]),
color: d[color_variable]
});
}
});

return arr;
}
Insert cell
Insert cell
x_domain = d3.extent(chart_data, d => d.x)
Insert cell
y_domain = d3.extent(chart_data, d => d.y)
Insert cell
color_domain = _.uniqBy(chart_data, d => d.color).map(d => d.color)
Insert cell
margin = ({ top: 80, right: 50, bottom: 50, left: 60 })
Insert cell
height = 500
Insert cell
x_scale = d3
.scaleLinear()
.domain(x_domain)
.range([margin.left, width - margin.right])
Insert cell
y_scale = d3
.scaleLinear()
.domain(y_domain)
.range([height - margin.bottom, margin.top])
Insert cell
Insert cell
x_axis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom().scale(x_scale))
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg.append("g").call(x_axis);

return svg.node();
}
Insert cell
y_axis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft().scale(y_scale))
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg.append("g").call(y_axis);

return svg.node();
}
Insert cell
import { legend } from "@d3/color-legend"
Insert cell
legend({
color: color
})
Insert cell
color = d3.scaleOrdinal(color_domain, d3.schemeCategory10)
Insert cell
{
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg
.append("g")
.call(x_axis);

svg
.append("g")
.call(y_axis);

return svg.node();
}
Insert cell
Insert cell
x_transform = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, 80]);

const selection = svg.selectAll("circle");
const circles = selection.data(data);
circles
.data(chart_data)
.join(
enter => enter.append("circle"),
update => update,
exit => exit.remove()
)
.attr("cx", d => x_scale(d.x))
.attr("r", 5)
.attr("opacity", .6)
.attr("cy", d => 40);

return svg.node();
}
Insert cell
y_transform = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const selection = svg.selectAll("circle");
const circles = selection.data(data);
circles
.data(chart_data)
.join(
enter => enter.append("circle"),
update => update,
exit => exit.remove()
)
.attr("cx", d => 40)
.attr("r", 5)
.attr("opacity", .5)
.attr("cy", d => y_scale(d.y));

return svg.node();
}
Insert cell
full_preview = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const selection = svg.selectAll("circle");
const circles = selection.data(data);
circles
.data(chart_data)
.join(
enter => enter.append("circle"),
update => update,
exit => exit.remove()
)
.attr("cx", d => x_scale(d.x))
.attr("r", 3)
.attr("opacity", .6)
.attr("fill", d => color(d.color))
.attr("cy", d => y_scale(d.y));

return svg.node();
}
Insert cell
Insert cell
Insert cell
scatterplot = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const selection = svg.selectAll("circle");
const circles = selection.data(data);
circles
.data(chart_data)
.join(
enter => enter.append("circle"),
update => update,
exit => exit.remove()
)
.transition()
.duration(800)
.attr("cx", d => x_scale(d.x))
.attr("r", 3)
.attr("opacity", .6)
.attr("fill", d => color(d.color))
.attr("cy", d => y_scale(d.y));

svg.append("g").call(x_axis);
svg.append("g").call(y_axis);
svg
.append("text")
.attr("x", width / 2)
.attr("y", height - 10)
.style("text-anchor", "middle")
.text(x_variable);
svg
.append("text")
.attr("class", "y label")
.attr("text-anchor", "middle")
.attr("y", 15)
.attr("x", -height / 2)
.attr("transform", "rotate(-90)")
.text(y_variable);
svg
.append("text")
.attr("x", width / 2)
.attr("y", 40)
.style("text-anchor", "middle")
.text(title);

return svg.node();
}
Insert cell
Insert cell
// Code adapted from here - https://observablehq.com/@d3/box-plot
boxplot = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const g = svg
.append("g")
.selectAll("g")
.data(bins)
.join("g");

g.append("path")
.attr("stroke", "currentColor")
.attr(
"d",
d => `
M${x_scale((d.x0 + d.x1) / 2)},${y_scale(d.range[1])}
V${y_scale(d.range[0])}
`
);

g.append("path")
.attr("fill", "#ddd")
.attr(
"d",
d => `
M${x_scale(d.x0) + 1},${y_scale(d.quartiles[2])}
H${x_scale(d.x1)}
V${y_scale(d.quartiles[0])}
H${x_scale(d.x0) + 1}
Z
`
);

g.append("path")
.attr("stroke", "currentColor")
.attr("stroke-width", 2)
.attr(
"d",
d => `
M${x_scale(d.x0) + 1},${y_scale(d.quartiles[1])}
H${x_scale(d.x1)}
`
);

g.append("g")
.attr("fill-opacity", 0.5)
.attr("stroke", "none")
.attr("transform", d => `translate(${x_scale((d.x0 + d.x1) / 2)},0)`)
.selectAll("circle")
.data(d => d.outliers)
.join("circle")
.attr("r", 2)
.attr("fill", d => color(d.color))
.attr("cx", () => (Math.random() - 0.5) * 4)
.attr("cy", d => y_scale(d.y));

svg.append("g").call(x_axis);
svg.append("g").call(y_axis);
svg
.append("text")
.attr("x", width / 2)
.attr("y", height - 10)
.style("text-anchor", "middle")
.text(x_variable);
svg
.append("text")
.attr("class", "y label")
.attr("text-anchor", "middle")
.attr("y", 15)
.attr("x", -height / 2)
.attr("transform", "rotate(-90)")
.text(y_variable);
svg
.append("text")
.attr("x", width / 2)
.attr("y", 40)
.style("text-anchor", "middle")
.text(title);

return svg.node();
}
Insert cell
// Code for bins adapted from here - https://observablehq.com/@d3/box-plot
bins = d3
.histogram()
.thresholds(x_domain[1] - x_domain[0])
.value(d => d.x)(chart_data)
.map(bin => {
bin.sort((a, b) => a.y - b.y);
const values = bin.map(d => d.y);
const min = values[0];
const max = values[values.length - 1];
const q1 = d3.quantile(values, 0.25);
const q2 = d3.quantile(values, 0.50);
const q3 = d3.quantile(values, 0.75);
const iqr = q3 - q1; // interquartile range
const r0 = Math.max(min, q1 - iqr * 1.5);
const r1 = Math.min(max, q3 + iqr * 1.5);
bin.quartiles = [q1, q2, q3];
bin.range = [r0, r1];
bin.outliers = bin.filter(v => v.y < r0 || v.y > r1);
return bin;
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more