Skill Library

advanced Data Science

D3.js Interactive Visualization

Create sophisticated, interactive data visualizations using D3.js. Build custom charts, graphs, and visual narratives that go beyond standard charting libraries with proper scales, axes, transitions, and responsive design.

When to Use This Skill

  • Creating custom visualizations not available in standard libraries
  • Building interactive data explorations
  • Visualizing hierarchical or network data
  • Creating animated data transitions
  • Building publication-quality graphics
  • Embedding visualizations in web applications
  • Creating data-driven storytelling experiences

How to use this skill

1. Copy the AI Core Logic from the Instructions tab below.

2. Paste it into your AI's System Instructions or as your first message.

3. Provide your raw data or requirements as requested by the AI.

#d3js#visualization#charts#data#interactive#svg#javascript

System Directives

## Curation Note D3.js remains the gold standard for custom data visualization on the web, but its learning curve is steep. This skill bridges the gap between understanding data and producing publication-quality visualizations. The approach emphasizes the "data join" paradigm that makes D3 powerful and the importance of proper scales, rather than hard-coded pixel values. Community feedback indicates this skill particularly helps when standard chart libraries (Chart.js, Plotly) lack the customization needed. ## Core Concepts ### The D3 Selection Pattern ```javascript // Select elements, bind data, modify d3.select('svg') .selectAll('circle') .data(dataset) .join('circle') .attr('cx', (d) => xScale(d.x)) .attr('cy', (d) => yScale(d.y)) .attr('r', (d) => rScale(d.value)); ``` ### The Data Join ```javascript // Enter, Update, Exit pattern const circles = svg.selectAll('circle').data(data); // Enter: new data points circles .enter() .append('circle') .attr('r', 0) .transition() .attr('r', (d) => rScale(d.value)); // Update: existing data points circles .transition() .attr('cx', (d) => xScale(d.x)) .attr('cy', (d) => yScale(d.y)); // Exit: removed data points circles.exit().transition().attr('r', 0).remove(); ``` ## Scales and Axes ### Linear Scale ```javascript const xScale = d3 .scaleLinear() .domain([0, d3.max(data, (d) => d.value)]) .range([margin.left, width - margin.right]); const yScale = d3 .scaleLinear() .domain([0, 100]) .range([height - margin.bottom, margin.top]); ``` ### Time Scale ```javascript const timeScale = d3 .scaleTime() .domain([new Date('2024-01-01'), new Date('2024-12-31')]) .range([margin.left, width - margin.right]); ``` ### Ordinal Scale ```javascript const colorScale = d3 .scaleOrdinal() .domain(['A', 'B', 'C']) .range(['#e41a1c', '#377eb8', '#4daf4a']); const bandScale = d3 .scaleBand() .domain(data.map((d) => d.category)) .range([margin.left, width - margin.right]) .padding(0.1); ``` ### Creating Axes ```javascript const xAxis = d3.axisBottom(xScale).ticks(5).tickFormat(d3.format('.0f')); const yAxis = d3.axisLeft(yScale).tickFormat((d) => `${d}%`); svg .append('g') .attr('transform', `translate(0,${height - margin.bottom})`) .call(xAxis); svg.append('g').attr('transform', `translate(${margin.left},0)`).call(yAxis); ``` ## Common Chart Patterns ### Bar Chart ```javascript function createBarChart(data, container) { const margin = { top: 20, right: 20, bottom: 30, left: 40 }; const width = 600 - 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})`); const x = d3 .scaleBand() .domain(data.map((d) => d.category)) .range([0, width]) .padding(0.1); const y = d3 .scaleLinear() .domain([0, d3.max(data, (d) => d.value)]) .nice() .range([height, 0]); svg .selectAll('.bar') .data(data) .join('rect') .attr('class', 'bar') .attr('x', (d) => x(d.category)) .attr('y', (d) => y(d.value)) .attr('width', x.bandwidth()) .attr('height', (d) => height - y(d.value)) .attr('fill', '#4e79a7'); svg.append('g').attr('transform', `translate(0,${height})`).call(d3.axisBottom(x)); svg.append('g').call(d3.axisLeft(y)); } ``` ### Line Chart with Area ```javascript function createLineChart(data, container) { const margin = { top: 20, right: 20, bottom: 30, left: 50 }; const width = 600; const height = 400; 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)]) .nice() .range([height - margin.bottom, margin.top]); const line = d3 .line() .x((d) => x(d.date)) .y((d) => y(d.value)) .curve(d3.curveMonotoneX); const area = d3 .area() .x((d) => x(d.date)) .y0(height - margin.bottom) .y1((d) => y(d.value)) .curve(d3.curveMonotoneX); const svg = d3.select(container).append('svg').attr('viewBox', `0 0 ${width} ${height}`); svg.append('path').datum(data).attr('fill', '#4e79a7').attr('fill-opacity', 0.2).attr('d', area); svg .append('path') .datum(data) .attr('fill', 'none') .attr('stroke', '#4e79a7') .attr('stroke-width', 2) .attr('d', line); } ``` ### Scatter Plot with Tooltip ```javascript function createScatterPlot(data, container) { const margin = { top: 20, right: 20, bottom: 40, left: 50 }; const width = 600; const height = 400; const x = d3 .scaleLinear() .domain(d3.extent(data, (d) => d.x)) .nice() .range([margin.left, width - margin.right]); const y = d3 .scaleLinear() .domain(d3.extent(data, (d) => d.y)) .nice() .range([height - margin.bottom, margin.top]); const svg = d3.select(container).append('svg').attr('viewBox', `0 0 ${width} ${height}`); // Tooltip const tooltip = d3 .select(container) .append('div') .attr('class', 'tooltip') .style('opacity', 0) .style('position', 'absolute'); svg .selectAll('circle') .data(data) .join('circle') .attr('cx', (d) => x(d.x)) .attr('cy', (d) => y(d.y)) .attr('r', 5) .attr('fill', '#4e79a7') .on('mouseover', (event, d) => { tooltip.transition().style('opacity', 0.9); tooltip .html(`X: ${d.x}<br>Y: ${d.y}`) .style('left', event.pageX + 10 + 'px') .style('top', event.pageY - 10 + 'px'); }) .on('mouseout', () => { tooltip.transition().style('opacity', 0); }); } ``` ## Animation and Transitions ```javascript // Smooth transitions svg .selectAll('rect') .data(newData) .transition() .duration(750) .ease(d3.easeCubicOut) .attr('height', (d) => height - y(d.value)) .attr('y', (d) => y(d.value)); // Staggered animation svg .selectAll('circle') .data(data) .join('circle') .attr('r', 0) .transition() .delay((d, i) => i * 50) .duration(500) .attr('r', 5); ``` ## Responsive Design ```javascript function makeResponsive(svg, width, height) { svg .attr('viewBox', `0 0 ${width} ${height}`) .attr('preserveAspectRatio', 'xMidYMid meet') .style('max-width', '100%') .style('height', 'auto'); } ``` ## Best Practices 1. **Always use scales** - Never hard-code pixel values 2. **Use viewBox for responsiveness** - Scales naturally 3. **Prefer data joins over manual DOM manipulation** 4. **Add transitions for data updates** - Helps users track changes 5. **Include axes with proper labels** - Context is essential 6. **Use semantic color scales** - Accessible to colorblind users 7. **Test with edge cases** - Empty data, extreme values ## Related Resources - [D3.js Documentation](https://d3js.org/) - [Observable D3 Gallery](https://observablehq.com/@d3/gallery) - [D3 Graph Gallery](https://www.d3-graph-gallery.com/)

Procedural Integration

This skill is formatted as a set of persistent system instructions. When integrated, it provides the AI model with specialized workflows and knowledge constraints for Data Science.

Skill Actions


Model Compatibility
🤖 Claude Opus🤖 Gemini 2.5 Pro
Code Execution: Required
MCP Tools: Optional
Footprint ~1,955 tokens