d3js-visualization

from bbeierle12/skill-mcp-claude

No description

4 stars0 forksUpdated Jan 23, 2026
npx skills add https://github.com/bbeierle12/skill-mcp-claude --skill d3js-visualization

SKILL.md

D3.js Visualization

Core Concepts

Selection and Data Binding

// Select elements
const svg = d3.select('#chart')
  .append('svg')
  .attr('width', width)
  .attr('height', height);

// Bind data to elements
svg.selectAll('rect')
  .data(data)
  .join('rect')
  .attr('x', (d, i) => i * barWidth)
  .attr('y', d => height - scale(d.value))
  .attr('width', barWidth - 1)
  .attr('height', d => scale(d.value));

Scales

// Linear scale (continuous → continuous)
const xScale = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.value)])
  .range([0, width]);

// Band scale (discrete → continuous)
const xScale = d3.scaleBand()
  .domain(data.map(d => d.name))
  .range([0, width])
  .padding(0.1);

// Time scale
const xScale = d3.scaleTime()
  .domain([startDate, endDate])
  .range([0, width]);

// Color scale
const colorScale = d3.scaleOrdinal(d3.schemeCategory10);

Axes

// Create axes
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);

// Append to SVG
svg.append('g')
  .attr('class', 'x-axis')
  .attr('transform', `translate(0, ${height})`)
  .call(xAxis);

svg.append('g')
  .attr('class', 'y-axis')
  .call(yAxis);

Common Chart Types

Bar Chart

function createBarChart(data, container, options = {}) {
  const {
    width = 600,
    height = 400,
    margin = { top: 20, right: 20, bottom: 30, left: 40 }
  } = options;

  const innerWidth = width - margin.left - margin.right;
  const innerHeight = height - margin.top - margin.bottom;

  const svg = d3.select(container)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  const g = svg.append('g')
    .attr('transform', `translate(${margin.left},${margin.top})`);

  const xScale = d3.scaleBand()
    .domain(data.map(d => d.name))
    .range([0, innerWidth])
    .padding(0.1);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.value)])
    .nice()
    .range([innerHeight, 0]);

  // Bars
  g.selectAll('.bar')
    .data(data)
    .join('rect')
    .attr('class', 'bar')
    .attr('x', d => xScale(d.name))
    .attr('y', d => yScale(d.value))
    .attr('width', xScale.bandwidth())
    .attr('height', d => innerHeight - yScale(d.value))
    .attr('fill', 'steelblue');

  // Axes
  g.append('g')
    .attr('transform', `translate(0,${innerHeight})`)
    .call(d3.axisBottom(xScale));

  g.append('g')
    .call(d3.axisLeft(yScale));

  return svg.node();
}

Line Chart

function createLineChart(data, container, options = {}) {
  const {
    width = 600,
    height = 400,
    margin = { top: 20, right: 20, bottom: 30, left: 40 }
  } = options;

  const innerWidth = width - margin.left - margin.right;
  const innerHeight = height - margin.top - margin.bottom;

  const svg = d3.select(container)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  const g = svg.append('g')
    .attr('transform', `translate(${margin.left},${margin.top})`);

  const xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, innerWidth]);

  const yScale = d3.scaleLinear()
    .domain([0, d3.max(data, d => d.value)])
    .nice()
    .range([innerHeight, 0]);

  // Line generator
  const line = d3.line()
    .x(d => xScale(d.date))
    .y(d => yScale(d.value))
    .curve(d3.curveMonotoneX);

  // Path
  g.append('path')
    .datum(data)
    .attr('fill', 'none')
    .attr('stroke', 'steelblue')
    .attr('stroke-width', 2)
    .attr('d', line);

  // Dots
  g.selectAll('.dot')
    .data(data)
    .join('circle')
    .attr('class', 'dot')
    .attr('cx', d => xScale(d.date))
    .attr('cy', d => yScale(d.value))
    .attr('r', 4)
    .attr('fill', 'steelblue');

  // Axes
  g.append('g')
    .attr('transform', `translate(0,${innerHeight})`)
    .call(d3.axisBottom(xScale));

  g.append('g')
    .call(d3.axisLeft(yScale));

  return svg.node();
}

Pie/Donut Chart

function createPieChart(data, container, options = {}) {
  const {
    width = 400,
    height = 400,
    innerRadius = 0, // 0 for pie, > 0 for donut
  } = options;

  const radius = Math.min(width, height) / 2;

  const svg = d3.select(container)
    .append('svg')
    .attr('width', width)
    .attr('height', height);

  const g = svg.append('g')
    .attr('transform', `translate(${width / 2},${height / 2})`);

  const color = d3.scaleOrdinal(d3.schemeCategory10);

  const pie = d3.pie()
    .value(d => d.value)
    .sort(null);

  const arc = d3.arc()
    .innerRadius(innerRadius)
    .outerRadius(radius - 10);

  const arcs = g.selectAll('.arc')
    .data(pie(data))
    .join('g')
    .attr('class', 'arc');

  arcs.append('path')
    .attr('d', arc)
    .attr('fill', d => color(d.data.name));

  arcs.append('text')
    .attr('transform', d => `translate(${arc.centroid(d)})`)
    .attr('text-anchor', 'middle')
    .text(d => d.data.name);

  return svg.node();
}

Interactivity

Tooltips

...

Read full content

Repository Stats

Stars4
Forks0