D3.js Reference for Coding Agents
prompts/pkg/llms/d3.md on every deploy, so it
can't drift from what the platform actually does. Read it from your terminal any
time with npx vibes-diy skills.
D3 (Data-Driven Documents) is a JavaScript library for creating bespoke data visualizations using web standards (SVG, Canvas, HTML). This guide provides essential patterns and examples for AI coding agents to create amazing D3 demonstrations.
Core Philosophy
D3 is a low-level toolbox of 30+ modules that work together. It's not a chart library but a collection of primitives for building custom visualizations. Think of it as "assembly language for data visualization."
Essential Setup
jsimport * as d3 from "d3";
// Or import specific modules
import { select, scaleLinear, line } from "d3";
The D3 Pattern: Select, Bind, Transform
Every D3 visualization follows this pattern:
- Select DOM elements
- Bind data to elements
- Transform elements based on data
js// Basic pattern
d3.select("body") // Select
.selectAll("div") // Select all divs
.data([4, 8, 15, 16]) // Bind data
.enter()
.append("div") // Enter new elements
.style("width", (d) => d * 10 + "px") // Transform
.text((d) => d);
Essential Modules & Quick Reference
1. d3-selection (DOM Manipulation)
js// Selection basics
d3.select("#chart"); // Select by ID
d3.selectAll(".bar"); // Select by class
selection.append("rect"); // Add element
selection.attr("width", 100); // Set attribute
selection.style("fill", "red"); // Set style
selection.text("Hello"); // Set text content
// Data joining (the D3 way)
const bars = svg.selectAll(".bar").data(data).enter().append("rect").attr("class", "bar");
2. d3-scale (Data Encoding)
js// Linear scale (continuous data)
const x = d3
.scaleLinear()
.domain([0, 100]) // Input range
.range([0, 500]); // Output range (pixels)
// Ordinal scale (categorical data)
const color = d3.scaleOrdinal().domain(["A", "B", "C"]).range(["red", "blue", "green"]);
// Time scale
const x = d3
.scaleTime()
.domain([new Date(2020, 0, 1), new Date(2024, 0, 1)])
.range([0, 800]);
// Band scale (for bar charts)
const x = d3
.scaleBand()
.domain(data.map((d) => d.name))
.range([0, width])
.padding(0.1);
3. d3-shape (SVG Path Generators)
js// Line generator
const line = d3
.line()
.x((d) => x(d.date))
.y((d) => y(d.value))
.curve(d3.curveCardinal); // Smooth curves
// Area generator
const area = d3
.area()
.x((d) => x(d.date))
.y0(y(0)) // Baseline
.y1((d) => y(d.value)); // Top line
// Arc generator (for pie charts)
const arc = d3.arc().innerRadius(0).outerRadius(radius);
4. d3-axis (Chart Axes)
js// Create axes
const xAxis = d3.axisBottom(x);
const yAxis = d3.axisLeft(y);
// Render axes
svg.append("g").attr("transform", `translate(0,${height})`).call(xAxis);
svg.append("g").call(yAxis);
5. d3-transition (Animation)
js// Smooth transitions
selection.transition().duration(1000).attr("width", newWidth).style("opacity", 0.5);
// Staggered transitions
bars
.transition()
.delay((d, i) => i * 100)
.duration(500)
.attr("height", (d) => y(d.value));
Complete Examples for Coding Agents
Code Structure for D3 + React Apps
Structure your component in this order:
- D3 helper functions — visualization logic separate from React
- Hooks and state — useFireproof, useRef, useState
- Effects — useEffect to call D3 helpers when data changes
- ClassNames object — colors, dimensions right before JSX so they stay consistent
- JSX return — layout with refs for D3 to target
1. Simple Bar Chart
jsimport * as d3 from "d3";
// 1. Design tokens and dimensions
const data = [4, 8, 15, 16, 23, 42];
const width = 500;
const height = 300;
const margin = {top: 20, right: 20, bottom: 30, left: 40};
const x = d3.scaleBand()
.domain(d3.range(data.length))
.range([margin.left, width - margin.right])
.padding(0.1);
const y = d3.scaleLinear()
.domain([0, d3.max(data)])
.range([height - margin.bottom, margin.top]);
const svg = d3.select("#chart")
.append("svg")
.attr("width", width)
.attr("height", height);
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", (d, i) => x(i))
.attr("y", d => y(d))
.attr("width", x.bandwidth())
.attr("height", d => height - margin.bottom - y(d))
.attr("fill", "steelblue");
// Add axes
svg.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));
svg.append("g")
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y));
2. Interactive Scatter Plot
jsimport * as d3 from "d3";
// Generate sample data
const data = d3.range(100).map(() => ({
x: Math.random() * 100,
y: Math.random() * 100,
radius: Math.random() * 10 + 2,
}));
const width = 600;
const height = 400;
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const x = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.x))
.range([margin.left, width - margin.right]);
const y = d3
.scaleLinear()
.domain(d3.extent(data, (d) => d.y))
.range([height - margin.bottom, margin.top]);
const svg = d3.select("#scatter").append("svg").attr("width", width).attr("height", height);
// Create circles with interactions
svg
.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx", (d) => x(d.x))
.attr("cy", (d) => y(d.y))
.attr("r", (d) => d.radius)
.attr("fill", "steelblue")
.attr("opacity", 0.7)
.on("mouseover", function (event, d) {
d3.select(this)
.transition()
.attr("r", d.radius * 1.5)
.attr("fill", "orange");
})
.on("mouseout", function (event, d) {
d3.select(this).transition().attr("r", d.radius).attr("fill", "steelblue");
});
// Add axes
svg
.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x));
svg.append("g").attr("transform", `translate(${margin.left},0)`).call(d3.axisLeft(y));
3. Force-Directed Network
jsimport * as d3 from "d3";
const nodes = d3.range(30).map((i) => ({ id: i }));
const links = d3.range(nodes.length - 1).map((i) => ({
source: Math.floor(Math.sqrt(i)),
target: i + 1,
}));
const width = 600;
const height = 400;
const svg = d3.select("#network").append("svg").attr("width", width).attr("height", height);
const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3.forceLink(links).id((d) => d.id)
)
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2));
const link = svg.append("g").selectAll("line").data(links).enter().append("line").attr("stroke", "#999").attr("stroke-width", 2);
const node = svg
.append("g")
.selectAll("circle")
.data(nodes)
.enter()
.append("circle")
.attr("r", 8)
.attr("fill", "steelblue")
.call(d3.drag().on("start", dragstarted).on("drag", dragged).on("end", dragended));
simulation.on("tick", () => {
link
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);
node.attr("cx", (d) => d.x).attr("cy", (d) => d.y);
});
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
4. Dynamic Line Chart with Real Data
jsimport * as d3 from "d3";
// Sample time series data
const data = d3.range(50).map((d, i) => ({
date: new Date(2024, 0, i + 1),
value: Math.sin(i * 0.1) * 50 + 50 + Math.random() * 20,
}));
const width = 700;
const height = 400;
const margin = { top: 20, right: 30, bottom: 40, left: 40 };
const x = d3
.scaleTime()
.domain(d3.extent(data, (d) => d.date))
.range([margin.left, width - margin.right]);
const y = d3
.scaleLinear()
.domain([0, d3.max(data, (d) => d.value)])
.range([height - margin.bottom, margin.top]);
const line = d3
.line()
.x((d) => x(d.date))
.y((d) => y(d.value))
.curve(d3.curveCardinal);
const svg = d3.select("#line-chart").append("svg").attr("width", width).attr("height", height);
// Add gradient definition
const gradient = svg
.append("defs")
.append("linearGradient")
.attr("id", "line-gradient")
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", 0)
.attr("y1", height)
.attr("x2", 0)
.attr("y2", 0);
gradient.append("stop").attr("offset", "0%").attr("stop-color", "lightblue").attr("stop-opacity", 0.1);
gradient.append("stop").attr("offset", "100%").attr("stop-color", "steelblue").attr("stop-opacity", 0.8);
// Draw line
svg.append("path").datum(data).attr("fill", "none").attr("stroke", "url(#line-gradient)").attr("stroke-width", 3).attr("d", line);
// Add dots with hover effects
svg
.selectAll(".dot")
.data(data)
.enter()
.append("circle")
.attr("class", "dot")
.attr("cx", (d) => x(d.date))
.attr("cy", (d) => y(d.value))
.attr("r", 4)
.attr("fill", "steelblue")
.on("mouseover", function (event, d) {
d3.select(this).attr("r", 6);
// Add tooltip
const tooltip = svg.append("g").attr("id", "tooltip");
tooltip
.append("rect")
.attr("x", x(d.date) + 10)
.attr("y", y(d.value) - 25)
.attr("width", 60)
.attr("height", 20)
.attr("fill", "black")
.attr("opacity", 0.8);
tooltip
.append("text")
.attr("x", x(d.date) + 15)
.attr("y", y(d.value) - 10)
.attr("fill", "white")
.style("font-size", "12px")
.text(d.value.toFixed(1));
})
.on("mouseout", function () {
d3.select(this).attr("r", 4);
svg.select("#tooltip").remove();
});
// Add axes
svg
.append("g")
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickFormat(d3.timeFormat("%b %d")));
svg.append("g").attr("transform", `translate(${margin.left},0)`).call(d3.axisLeft(y));
Key Modules Cheat Sheet
Scales (Data Encoding)
js// Continuous scales
d3.scaleLinear(); // Numbers to numbers
d3.scaleTime(); // Dates to numbers
d3.scalePow(); // Power/sqrt scales
d3.scaleLog(); // Logarithmic scales
// Discrete scales
d3.scaleOrdinal(); // Categories to values
d3.scaleBand(); // Categories to positions (bar charts)
d3.scalePoint(); // Categories to points
// Color scales
d3.scaleSequential(d3.interpolateViridis); // Continuous colors
d3.scaleOrdinal(d3.schemeCategory10); // Categorical colors
Shapes (SVG Path Generators)
js// Lines and areas
d3.line().x(x).y(y);
d3.area().x(x).y0(y0).y1(y1);
// Arcs and pies
d3.arc().innerRadius(r1).outerRadius(r2);
d3.pie().value((d) => d.value);
// Symbols (scatter plot markers)
d3.symbol().type(d3.symbolCircle).size(100);
Arrays (Data Processing)
js// Statistics
d3.min(data, (d) => d.value);
d3.max(data, (d) => d.value);
d3.extent(data, (d) => d.value); // [min, max]
d3.mean(data, (d) => d.value);
d3.median(data, (d) => d.value);
// Grouping and nesting
d3.group(data, (d) => d.category);
d3.rollup(
data,
(v) => v.length,
(d) => d.category
);
// Sorting
d3.ascending(a, b);
d3.descending(a, b);
Forces (Physics Simulations)
jsconst simulation = d3
.forceSimulation(nodes)
.force("link", d3.forceLink(links))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide().radius(10));
Common Patterns for Amazing Demos
1. Responsive SVG Setup
jsconst container = d3.select("#chart");
const svg = container.append("svg").attr("viewBox", `0 0 ${width} ${height}`).style("max-width", "100%").style("height", "auto");
2. Smooth Data Updates
jsfunction updateChart(newData) {
const bars = svg.selectAll(".bar").data(newData);
// Update existing
bars
.transition()
.duration(750)
.attr("height", (d) => y(d.value));
// Add new
bars
.enter()
.append("rect")
.attr("class", "bar")
.attr("height", 0)
.transition()
.duration(750)
.attr("height", (d) => y(d.value));
// Remove old
bars.exit().transition().duration(750).attr("height", 0).remove();
}
3. Color Schemes
js// Beautiful built-in color schemes
d3.schemeCategory10; // 10 categorical colors
d3.schemeSet3; // 12 pastel colors
d3.interpolateViridis; // Blue to yellow gradient
d3.interpolatePlasma; // Purple to yellow gradient
d3.schemePaired; // Paired categorical colors
// Usage
const color = d3.scaleOrdinal(d3.schemeCategory10);
4. Tooltips and Interactions
js// Create tooltip div
const tooltip = d3.select("body").append("div")
.style("position", "absolute")
.style("padding", "10px")
.style("background", "rgba(0,0,0,0.8)")
.style("color", "white")
.style("border-radius", "5px")
.style("pointer-events", "none")
.style("opacity", 0);
// Add to elements
.on("mouseover", function(event, d) {
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`Value: ${d.value}`)
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", function() {
tooltip.transition().duration(500).style("opacity", 0);
});
5. Data Loading and Processing
js// Load CSV data
d3.csv("data.csv").then((data) => {
// Process data
data.forEach((d) => {
d.value = +d.value; // Convert to number
d.date = d3.timeParse("%Y-%m-%d")(d.date); // Parse dates
});
// Create visualization
createChart(data);
});
// Load JSON data
d3.json("data.json").then(createChart);
Pro Tips for Coding Agents
- Start with the canvas: Set up SVG dimensions and margins first
- Define scales early: Map your data domain to visual range before drawing
- Use method chaining: D3's fluent API allows
selection.attr().style().on() - Leverage data joins: Use enter/update/exit pattern for dynamic data
- Add transitions:
transition().duration(500)makes everything better - Use color schemes: Built-in color palettes save time and look professional
- Make it responsive: Use viewBox for scalable graphics
- Add interactions: hover, click, drag make demos engaging
- Consider performance: Use Canvas for 1000+ elements, SVG for detailed graphics
- Test with real data: Random data is fine for prototypes, realistic data for demos
Quick Chart Types
Bar Chart: d3.scaleBand() + rect elements
Line Chart: d3.line() + path element
Scatter Plot: circle elements with cx, cy from scales
Pie Chart: d3.pie() + d3.arc() + path elements
Network: d3.forceSimulation() + line + circle elements
Map: d3.geoPath() + GeoJSON data
Treemap: d3.treemap() + hierarchical data
Heatmap: rect grid + d3.scaleSequential() colors
Framework Integration
React
jsx// Use refs for D3 DOM manipulation
const svgRef = useRef();
useEffect(() => {
const svg = d3.select(svgRef.current);
// D3 code here...
}, [data]);
return <svg ref={svgRef}></svg>;
Performance & Best Practices
- Use
d3.select()for single elements,d3.selectAll()for multiple - Cache selections when reusing:
const bars = svg.selectAll(".bar") - Use Canvas for 1000+ data points, SVG for interactive/detailed graphics
- Debounce resize events for responsive charts
- Use
d3.csv(),d3.json()for async data loading - Leverage D3's built-in interpolators for smooth animations
This reference focuses on practical patterns for creating impressive D3 demonstrations. Each example is self-contained and copy-pasteable for rapid prototyping.