S

Smart D3 Data Visualization Engine

Streamline your workflow with this skill for create interactive charts and data visualizations. Built for Claude Code with best practices and real-world patterns.

SkillCommunitydevelopmentv1.0.0MIT
0 views0 copies

D3 Data Visualization Engine

A data visualization skill for building interactive, publication-quality charts, maps, and data graphics using D3.js with responsive layouts and animated transitions.

When to Use

Choose D3 Data Visualization when:

  • Building custom, interactive data visualizations beyond standard chart libraries
  • Creating complex visualizations like force-directed graphs, treemaps, or geographic maps
  • Implementing animated data transitions and interactive data exploration
  • Building reusable chart components for dashboards and data products

Consider alternatives when:

  • Standard charts (bar, line, pie) suffice — use Chart.js or Recharts
  • Quick data exploration — use Observable notebooks or Jupyter
  • No interactivity needed — use Matplotlib or ggplot2

Quick Start

npm install d3
import * as d3 from 'd3'; // Responsive bar chart function createBarChart(container: string, data: Array<{label: string; value: number}>) { const margin = { top: 20, right: 30, bottom: 40, left: 50 }; const width = 800 - margin.left - margin.right; const height = 400 - margin.top - margin.bottom; const svg = d3.select(container) .append('svg') .attr('viewBox', `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`) .append('g') .attr('transform', `translate(${margin.left},${margin.top})`); // Scales const x = d3.scaleBand() .domain(data.map(d => d.label)) .range([0, width]) .padding(0.2); const y = d3.scaleLinear() .domain([0, d3.max(data, d => d.value)!]) .nice() .range([height, 0]); // Axes svg.append('g') .attr('transform', `translate(0,${height})`) .call(d3.axisBottom(x)); svg.append('g') .call(d3.axisLeft(y).ticks(5)); // Bars with animation svg.selectAll('.bar') .data(data) .join('rect') .attr('class', 'bar') .attr('x', d => x(d.label)!) .attr('width', x.bandwidth()) .attr('y', height) // Start from bottom .attr('height', 0) .attr('fill', '#4472C4') .attr('rx', 4) .transition() .duration(800) .delay((_, i) => i * 100) .attr('y', d => y(d.value)) .attr('height', d => height - y(d.value)); // Tooltip const tooltip = d3.select(container) .append('div') .attr('class', 'tooltip') .style('opacity', 0) .style('position', 'absolute') .style('background', 'rgba(0,0,0,0.8)') .style('color', 'white') .style('padding', '8px 12px') .style('border-radius', '4px') .style('font-size', '14px'); svg.selectAll('.bar') .on('mouseover', (event, d) => { tooltip.transition().duration(200).style('opacity', 1); tooltip.html(`${d.label}: ${d.value}`) .style('left', event.pageX + 10 + 'px') .style('top', event.pageY - 28 + 'px'); d3.select(event.currentTarget).attr('fill', '#2a5599'); }) .on('mouseout', (event) => { tooltip.transition().duration(500).style('opacity', 0); d3.select(event.currentTarget).attr('fill', '#4472C4'); }); }

Core Concepts

D3 Core Modules

ModulePurposeKey Functions
d3-selectionDOM manipulationselect, selectAll, join
d3-scaleData-to-visual mappingscaleLinear, scaleBand, scaleOrdinal
d3-axisAxis renderingaxisBottom, axisLeft
d3-shapeShape generatorsline, arc, area, pie
d3-transitionAnimated transitionstransition, duration, ease
d3-geoGeographic projectionsgeoPath, geoMercator
d3-hierarchyTree/network layoutstree, treemap, pack
d3-forceForce-directed layoutsforceSimulation, forceLink

Reusable Chart Pattern

function lineChart() { let width = 600; let height = 400; let xAccessor = (d: any) => d.x; let yAccessor = (d: any) => d.y; let color = '#4472C4'; function chart(selection: d3.Selection<any, any, any, any>) { selection.each(function(data) { const svg = d3.select(this).selectAll('svg') .data([data]).join('svg') .attr('viewBox', `0 0 ${width} ${height}`); const x = d3.scaleTime() .domain(d3.extent(data, xAccessor) as [Date, Date]) .range([50, width - 20]); const y = d3.scaleLinear() .domain([0, d3.max(data, yAccessor)!]) .nice() .range([height - 30, 20]); const line = d3.line<any>() .x(d => x(xAccessor(d))) .y(d => y(yAccessor(d))) .curve(d3.curveMonotoneX); svg.selectAll('.line') .data([data]).join('path') .attr('class', 'line') .attr('d', line) .attr('fill', 'none') .attr('stroke', color) .attr('stroke-width', 2); }); } // Chainable setters chart.width = (v: number) => { width = v; return chart; }; chart.height = (v: number) => { height = v; return chart; }; chart.x = (v: (d: any) => any) => { xAccessor = v; return chart; }; chart.y = (v: (d: any) => any) => { yAccessor = v; return chart; }; chart.color = (v: string) => { color = v; return chart; }; return chart; }

Configuration

OptionDescriptionDefault
widthChart width (or viewport-relative)800
heightChart height400
marginsChart margins object{ top: 20, right: 30, bottom: 40, left: 50 }
color_schemeD3 color schemed3.schemeCategory10
transition_durationAnimation duration (ms)800
responsiveUse viewBox for responsive sizingtrue
tooltipEnable interactive tooltipstrue
grid_linesShow background gridfalse

Best Practices

  1. Use viewBox instead of fixed width/height to make charts responsive — viewBox scales the SVG to fit its container while maintaining aspect ratio, eliminating the need for manual resize handlers
  2. Implement the General Update Pattern with .join() for data binding instead of the older .enter().append() pattern — .join() handles enter, update, and exit selections cleanly in one call
  3. Create reusable chart functions using the module pattern with chainable setters so chart configuration is separate from data binding and rendering logic
  4. Add transitions for data changes to help users track how values change between states — animate from old positions to new ones rather than instantly replacing the visualization
  5. Use semantic color scales that convey meaning (red for negative, green for positive) and ensure accessibility by not relying solely on color to distinguish data series; add patterns, labels, or shapes as well

Common Issues

Transitions conflicting when data updates rapidly: Multiple transitions on the same element override each other, causing flickering. Use .interrupt() before starting new transitions, or use named transitions to prevent conflicts between different animation chains.

SVG performance with thousands of elements: Rendering 10,000+ SVG elements causes visible lag and poor interaction performance. Switch to Canvas rendering for large datasets, aggregate data before visualization, or use virtual rendering that only draws elements currently in the viewport.

Axis labels overlapping on small screens: Long category labels on the x-axis overlap when there are many data points. Rotate labels with .attr('transform', 'rotate(-45)'), truncate long text, or switch to a horizontal bar chart layout for many categories.

Community

Reviews

Write a review

No reviews yet. Be the first to review this template!

Similar Templates