Vibes DIY
Vibes DIY / Docs / Reference
creator docs · reference · generated

D3.js Reference for Coding Agents

This is the same document the Vibes code generator reads when it builds apps — rendered from 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:

  1. Select DOM elements
  2. Bind data to elements
  3. 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:

  1. D3 helper functions — visualization logic separate from React
  2. Hooks and state — useFireproof, useRef, useState
  3. Effects — useEffect to call D3 helpers when data changes
  4. ClassNames object — colors, dimensions right before JSX so they stay consistent
  5. 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

  1. Start with the canvas: Set up SVG dimensions and margins first
  2. Define scales early: Map your data domain to visual range before drawing
  3. Use method chaining: D3's fluent API allows selection.attr().style().on()
  4. Leverage data joins: Use enter/update/exit pattern for dynamic data
  5. Add transitions: transition().duration(500) makes everything better
  6. Use color schemes: Built-in color palettes save time and look professional
  7. Make it responsive: Use viewBox for scalable graphics
  8. Add interactions: hover, click, drag make demos engaging
  9. Consider performance: Use Canvas for 1000+ elements, SVG for detailed graphics
  10. 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.