d3js

D3.js Data Visualization Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "d3js" with this command: npx skills add vamseeachanta/workspace-hub/vamseeachanta-workspace-hub-d3js

D3.js Data Visualization Skill

Create powerful, custom data visualizations using D3.js for complete control over SVG elements, transitions, and data binding.

When to Use This Skill

Use D3.js when you need:

  • Complete customization - Every aspect of the visualization controlled

  • Complex interactions - Advanced user interactions and transitions

  • Unique visualizations - Bespoke charts not available in other libraries

  • Data-driven DOM manipulation - Direct binding of data to DOM elements

  • Custom animations - Sophisticated transitions and effects

Avoid when:

  • Simple charts with default styling are sufficient (use Chart.js)

  • Quick implementation is priority (use Plotly or Chart.js)

  • Team lacks JavaScript expertise

Core Capabilities

  1. Data Binding

// Select and bind data to elements d3.select('#chart') .selectAll('circle') .data(dataset) .enter() .append('circle') .attr('cx', d => xScale(d.x)) .attr('cy', d => yScale(d.y)) .attr('r', d => d.radius) .style('fill', d => colorScale(d.category));

  1. Scales and Axes

// Create scales for positioning const xScale = d3.scaleLinear() .domain([0, d3.max(data, d => d.x)]) .range([0, width]);

const yScale = d3.scaleLinear() .domain([0, d3.max(data, d => d.y)]) .range([height, 0]);

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

svg.append('g') .attr('transform', translate(0, ${height})) .call(xAxis);

svg.append('g') .call(yAxis);

  1. Transitions and Animations

// Smooth transitions d3.selectAll('circle') .transition() .duration(1000) .attr('r', d => d.newRadius) .style('fill', 'steelblue');

  1. Interactive Elements

// Add interactivity const tooltip = d3.select('body') .append('div') .attr('class', 'tooltip') .style('opacity', 0);

circles .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(d) { tooltip.transition() .duration(500) .style('opacity', 0); });

Complete Examples

Example 1: Interactive Bar Chart

<!DOCTYPE html> <html> <head> <script src="https://d3js.org/d3.v7.min.js">&#x3C;/script> <style> .bar { fill: steelblue; cursor: pointer; } .bar:hover { fill: orange; } .tooltip { position: absolute; padding: 10px; background: rgba(0,0,0,0.8); color: white; border-radius: 5px; pointer-events: none; } </style> </head> <body> <div id="chart"></div> <script> // Data const data = [ { category: 'A', value: 30 }, { category: 'B', value: 80 }, { category: 'C', value: 45 }, { category: 'D', value: 60 }, { category: 'E', value: 20 } ];

// Dimensions
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;

// Create SVG
const svg = d3.select('#chart')
  .append('svg')
  .attr('width', width + margin.left + margin.right)
  .attr('height', height + margin.top + margin.bottom)
  .append('g')
  .attr('transform', `translate(${margin.left},${margin.top})`);

// Scales
const xScale = d3.scaleBand()
  .domain(data.map(d => d.category))
  .range([0, width])
  .padding(0.1);

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

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

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

// Tooltip
const tooltip = d3.select('body')
  .append('div')
  .attr('class', 'tooltip')
  .style('opacity', 0);

// Bars
svg.selectAll('.bar')
  .data(data)
  .enter()
  .append('rect')
  .attr('class', 'bar')
  .attr('x', d => xScale(d.category))
  .attr('y', d => yScale(d.value))
  .attr('width', xScale.bandwidth())
  .attr('height', d => height - yScale(d.value))
  .on('mouseover', function(event, d) {
    d3.select(this).style('fill', 'orange');
    tooltip.transition().duration(200).style('opacity', .9);
    tooltip.html(`${d.category}: ${d.value}`)
      .style('left', (event.pageX + 10) + 'px')
      .style('top', (event.pageY - 28) + 'px');
  })
  .on('mouseout', function(d) {
    d3.select(this).style('fill', 'steelblue');
    tooltip.transition().duration(500).style('opacity', 0);
  });

</script> </body> </html>

Example 2: Animated Line Chart with CSV Data

// Load and visualize CSV data d3.csv('../data/timeseries.csv').then(data => { // Parse dates and values const parseDate = d3.timeParse('%Y-%m-%d'); data.forEach(d => { d.date = parseDate(d.date); d.value = +d.value; });

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

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

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

// Draw line with animation const path = svg.append('path') .datum(data) .attr('class', 'line') .attr('d', line) .style('fill', 'none') .style('stroke', 'steelblue') .style('stroke-width', 2);

// Animate path const totalLength = path.node().getTotalLength(); path .attr('stroke-dasharray', totalLength + ' ' + totalLength) .attr('stroke-dashoffset', totalLength) .transition() .duration(2000) .ease(d3.easeLinear) .attr('stroke-dashoffset', 0);

// Add dots svg.selectAll('.dot') .data(data) .enter() .append('circle') .attr('class', 'dot') .attr('cx', d => xScale(d.date)) .attr('cy', d => yScale(d.value)) .attr('r', 0) .style('fill', 'steelblue') .transition() .delay((d, i) => i * 50) .duration(500) .attr('r', 4); });

Example 3: Force-Directed Network Graph

// Network data const nodes = [ { id: 'A', group: 1 }, { id: 'B', group: 1 }, { id: 'C', group: 2 }, { id: 'D', group: 2 }, { id: 'E', group: 3 } ];

const links = [ { source: 'A', target: 'B', value: 1 }, { source: 'B', target: 'C', value: 2 }, { source: 'C', target: 'D', value: 1 }, { source: 'D', target: 'E', value: 3 }, { source: 'E', target: 'A', value: 2 } ];

// Create force simulation const simulation = d3.forceSimulation(nodes) .force('link', d3.forceLink(links).id(d => d.id)) .force('charge', d3.forceManyBody().strength(-200)) .force('center', d3.forceCenter(width / 2, height / 2));

// Draw links const link = svg.append('g') .selectAll('line') .data(links) .enter() .append('line') .style('stroke', '#999') .style('stroke-width', d => Math.sqrt(d.value));

// Draw nodes const node = svg.append('g') .selectAll('circle') .data(nodes) .enter() .append('circle') .attr('r', 10) .style('fill', d => d3.schemeCategory10[d.group]) .call(d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended));

// Add labels const label = svg.append('g') .selectAll('text') .data(nodes) .enter() .append('text') .text(d => d.id) .style('font-size', '12px') .attr('dx', 12) .attr('dy', 4);

// Update positions on tick 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);

label .attr('x', d => d.x) .attr('y', d => d.y); });

// Drag functions function dragstarted(event, d) { if (!event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; }

function dragged(event, d) { d.fx = event.x; d.fy = event.y; }

function dragended(event, d) { if (!event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; }

Best Practices

  1. Use Proper Margins Convention

const margin = { top: 20, right: 20, bottom: 30, left: 40 }; const width = 960 - margin.left - margin.right; const height = 500 - margin.top - margin.bottom;

const svg = d3.select('body').append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append('g') .attr('transform', translate(${margin.left},${margin.top}));

  1. Use Method Chaining

// Good - readable chaining svg.selectAll('circle') .data(data) .enter() .append('circle') .attr('cx', d => xScale(d.x)) .attr('cy', d => yScale(d.y)) .attr('r', 5);

  1. Separate Data from Presentation

// Load data separately d3.json('../data/data.json').then(data => { visualize(data); });

function visualize(data) { // Visualization logic here }

  1. Use Responsive Design

// Make chart responsive function resize() { const container = d3.select('#chart').node(); const width = container.getBoundingClientRect().width;

xScale.range([0, width]); svg.attr('width', width); // Update chart elements }

window.addEventListener('resize', resize);

Common Patterns

Update Pattern (Enter, Update, Exit)

function update(data) { // Bind data const circles = svg.selectAll('circle') .data(data, d => d.id);

// EXIT: Remove old elements circles.exit() .transition() .duration(500) .attr('r', 0) .remove();

// UPDATE: Update existing elements circles .transition() .duration(500) .attr('cx', d => xScale(d.x)) .attr('cy', d => yScale(d.y));

// ENTER: Add new elements circles.enter() .append('circle') .attr('r', 0) .attr('cx', d => xScale(d.x)) .attr('cy', d => yScale(d.y)) .transition() .duration(500) .attr('r', 5); }

Brush and Zoom

// Add zoom behavior const zoom = d3.zoom() .scaleExtent([1, 10]) .on('zoom', zoomed);

svg.call(zoom);

function zoomed(event) { const transform = event.transform; svg.attr('transform', transform); }

// Add brush selection const brush = d3.brush() .extent([[0, 0], [width, height]]) .on('end', brushed);

svg.append('g') .attr('class', 'brush') .call(brush);

function brushed(event) { if (!event.selection) return; const [[x0, y0], [x1, y1]] = event.selection; // Handle selected region }

Installation & Setup

CDN (Quick Start)

<script src="https://d3js.org/d3.v7.min.js">&#x3C;/script>

NPM (Production)

npm install d3

import * as d3 from 'd3'; // Or import specific modules import { select, scaleLinear, axisBottom } from 'd3';

Performance Tips

  • Minimize DOM operations - Batch updates when possible

  • Use canvas for large datasets - Switch to canvas for >1000 points

  • Throttle events - Debounce mousemove/scroll events

  • Optimize transitions - Limit concurrent animations

  • Use web workers - Offload heavy computations

Resources

Integration with Other Tools

With React

import { useEffect, useRef } from 'react'; import * as d3 from 'd3';

function D3Chart({ data }) { const svgRef = useRef();

useEffect(() => { const svg = d3.select(svgRef.current); // D3 code here }, [data]);

return <svg ref={svgRef}></svg>; }

With CSV/JSON Data

// Load from relative path d3.csv('../data/data.csv').then(data => { // Process and visualize });

d3.json('../data/data.json').then(data => { // Visualize JSON });

Use this skill when you need maximum control and customization in your data visualizations!

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

echarts

No summary provided by upstream source.

Repository SourceNeeds Review
General

pandoc

No summary provided by upstream source.

Repository SourceNeeds Review
General

mkdocs

No summary provided by upstream source.

Repository SourceNeeds Review
General

gis

No summary provided by upstream source.

Repository SourceNeeds Review