JavaScript D3.js
Data-Driven Documents for powerful data visualizations
🎯 What is D3.js?
D3.js (Data-Driven Documents) is a powerful JavaScript library for creating dynamic, interactive data visualizations using web standards like HTML, SVG, and CSS. It gives you complete control over the final result.
<!-- Include D3.js -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- SVG container -->
<svg id="myChart" width="400" height="200"></svg>
<script>
// Simple bar chart with D3
const data = [30, 86, 168, 281, 303, 365];
d3.select("#myChart")
.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => i * 60)
.attr("y", d => 200 - d)
.attr("width", 50)
.attr("height", d => d)
.attr("fill", "steelblue");
</script>
Output:
D3.js Core Concepts
Selections
Select and manipulate DOM elements
d3.select("body").selectAll("p")
Data Binding
Bind data to DOM elements
.data(dataset).enter()
Scales
Map data values to visual properties
d3.scaleLinear().domain().range()
SVG Graphics
Create scalable vector graphics
.append("circle").attr("r", 5)
🔹 Creating a Scatter Plot
Scatter plots show relationships between two variables:
// Sample data
const dataset = [
[5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
[410, 12], [475, 44], [25, 67], [85, 21], [220, 88]
];
// Set dimensions and margins
const margin = {top: 20, right: 20, bottom: 30, left: 40};
const width = 400 - margin.left - margin.right;
const height = 300 - margin.top - margin.bottom;
// Create SVG
const svg = d3.select("#scatterPlot")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Create scales
const xScale = d3.scaleLinear()
.domain([0, d3.max(dataset, d => d[0])])
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(dataset, d => d[1])])
.range([height, 0]);
// Add circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle")
.attr("cx", d => xScale(d[0]))
.attr("cy", d => yScale(d[1]))
.attr("r", 5)
.attr("fill", "orange");
Output:
🔹 Interactive Bar Chart
Add interactivity with mouse events and transitions:
const data = [12, 5, 6, 6, 9, 10];
const width = 420;
const barHeight = 20;
const x = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([0, width]);
const chart = d3.select("#barChart")
.append("svg")
.attr("width", width)
.attr("height", barHeight * data.length);
const bar = chart.selectAll("g")
.data(data)
.enter().append("g")
.attr("transform", (d, i) => `translate(0,${i * barHeight})`);
bar.append("rect")
.attr("width", x)
.attr("height", barHeight - 1)
.attr("fill", "steelblue")
.on("mouseover", function() {
d3.select(this).attr("fill", "orange");
})
.on("mouseout", function() {
d3.select(this).attr("fill", "steelblue");
});
bar.append("text")
.attr("x", d => x(d) - 3)
.attr("y", barHeight / 2)
.attr("dy", ".35em")
.style("fill", "white")
.text(d => d);
Output: (Hover over the bars)
🔹 Animated Transitions
D3 makes it easy to add smooth animations:
// Create circles that grow on click
const svg = d3.select("#animationDemo")
.append("svg")
.attr("width", 400)
.attr("height", 200);
const circles = svg.selectAll("circle")
.data([1, 2, 3, 4, 5])
.enter()
.append("circle")
.attr("cx", (d, i) => (i * 70) + 50)
.attr("cy", 100)
.attr("r", 20)
.attr("fill", "lightblue")
.style("cursor", "pointer");
// Add click animation
circles.on("click", function() {
d3.select(this)
.transition()
.duration(500)
.attr("r", 40)
.attr("fill", "red")
.transition()
.duration(500)
.attr("r", 20)
.attr("fill", "lightblue");
});
Output: (Click on the circles)
🔹 D3.js Boilerplate Template
A complete starter template for D3.js projects:
<!DOCTYPE html>
<html>
<head>
<title>D3.js Visualization</title>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.chart-container {
margin: 20px 0;
border: 1px solid #ddd;
border-radius: 5px;
padding: 15px;
}
.axis {
font-size: 12px;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.tooltip {
position: absolute;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 5px;
pointer-events: none;
opacity: 0;
}
</style>
</head>
<body>
<h1>D3.js Data Visualization Dashboard</h1>
<div class="chart-container">
<h2>Interactive Bar Chart</h2>
<div id="barChart"></div>
</div>
<div class="chart-container">
<h2>Scatter Plot with Axes</h2>
<div id="scatterPlot"></div>
</div>
<div class="tooltip"></div>
<script>
// Sample data
const barData = [
{name: 'A', value: 30},
{name: 'B', value: 80},
{name: 'C', value: 45},
{name: 'D', value: 60},
{name: 'E', value: 20},
{name: 'F', value: 90}
];
const scatterData = [
{x: 10, y: 20, category: 'Type A'},
{x: 40, y: 90, category: 'Type B'},
{x: 25, y: 50, category: 'Type A'},
{x: 60, y: 70, category: 'Type C'},
{x: 80, y: 30, category: 'Type B'}
];
// Chart dimensions
const margin = {top: 20, right: 20, bottom: 40, left: 40};
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
// Create tooltip
const tooltip = d3.select(".tooltip");
// Bar Chart
function createBarChart() {
const svg = d3.select("#barChart")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
const xScale = d3.scaleBand()
.domain(barData.map(d => d.name))
.range([0, width])
.padding(0.1);
const yScale = d3.scaleLinear()
.domain([0, d3.max(barData, d => d.value)])
.range([height, 0]);
// Add bars
svg.selectAll(".bar")
.data(barData)
.enter().append("rect")
.attr("class", "bar")
.attr("x", d => xScale(d.name))
.attr("width", xScale.bandwidth())
.attr("y", d => yScale(d.value))
.attr("height", d => height - yScale(d.value))
.attr("fill", "steelblue")
.on("mouseover", function(event, d) {
d3.select(this).attr("fill", "orange");
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`${d.name}: ${d.value}`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", function() {
d3.select(this).attr("fill", "steelblue");
tooltip.transition().duration(500).style("opacity", 0);
});
// Add axes
svg.append("g")
.attr("class", "axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale));
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(yScale));
}
// Scatter Plot
function createScatterPlot() {
const svg = d3.select("#scatterPlot")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
const xScale = d3.scaleLinear()
.domain([0, d3.max(scatterData, d => d.x)])
.range([0, width]);
const yScale = d3.scaleLinear()
.domain([0, d3.max(scatterData, d => d.y)])
.range([height, 0]);
const colorScale = d3.scaleOrdinal()
.domain(['Type A', 'Type B', 'Type C'])
.range(['#ff7f0e', '#2ca02c', '#d62728']);
// Add circles
svg.selectAll(".dot")
.data(scatterData)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 8)
.attr("cx", d => xScale(d.x))
.attr("cy", d => yScale(d.y))
.attr("fill", d => colorScale(d.category))
.on("mouseover", function(event, d) {
d3.select(this).attr("r", 12);
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`${d.category}<br/>X: ${d.x}, Y: ${d.y}`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", function() {
d3.select(this).attr("r", 8);
tooltip.transition().duration(500).style("opacity", 0);
});
// Add axes
svg.append("g")
.attr("class", "axis")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(xScale));
svg.append("g")
.attr("class", "axis")
.call(d3.axisLeft(yScale));
}
// Initialize charts
createBarChart();
createScatterPlot();
</script>
</body>
</html>