Build deterministic, verifiable data visualizations with D3.js (v6). Generate standalone HTML/SVG (and optional PNG) from local data files without external network dependencies. Use when tasks require charts, plots, axes/scales, legends, tooltips, or data-driven SVG output.
Use this skill to turn structured data (CSV/TSV/JSON) into clean, reproducible visualizations using D3.js. The goal is to produce stable outputs that can be verified by diffing files or hashing.
Activate this skill when the user asks for any of the following:
If the user only needs a quick table or summary, don’t use D3—use a spreadsheet or plain markdown instead.
*.csv, *.tsv, *.jsonIf details are missing, make reasonable defaults and document them in comments near the top of the output file.
Prefer producing all of the following when feasible:
dist/chart.html — standalone HTML that renders the visualizationdist/chart.svg — exported SVG (stable and diff-friendly)dist/chart.png — if the task explicitly needs a raster imageAlways keep outputs in a predictable folder (default: dist/), unless the task specifies paths.
To keep results stable across runs and machines:
Array.from(grouped.keys()).sort()).d3.format, d3.timeFormat with explicit formats).Math.random() or d3-random.width, height, margin, viewBox.vendor/d3.v7.9.0.min.js) or bundling with a lockfile."clip-plot").If the task doesn't specify an existing structure, use:
dist/
chart.html # standalone HTML with inline or linked JS/CSS
chart.svg # exported SVG (optional but nice)
chart.png # rasterized (optional)
vendor/
d3.v7.9.0.min.js # pinned D3 library
When the task requires interactivity (e.g., tooltips on hover, click to highlight):
<div id="tooltip" class="tooltip"></div>
.visible class for show/hide:.tooltip {
position: absolute;
padding: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
border-radius: 4px;
pointer-events: none; /* Prevent mouse interference */
opacity: 0;
transition: opacity 0.2s;
z-index: 1000;
}
.tooltip.visible {
opacity: 1; /* Show when .visible class is added */
}
svg.selectAll('circle')
.on('mouseover', function(event, d) {
d3.select('#tooltip')
.classed('visible', true) // Add .visible class
.html(`<strong>${d.name}</strong><br/>${d.value}`)
.style('left', (event.pageX + 10) + 'px')
.style('top', (event.pageY - 10) + 'px');
})
.on('mouseout', function() {
d3.select('#tooltip').classed('visible', false); // Remove .visible class
});
Key points:
opacity: 0 by default (not display: none) for smooth transitions.classed('visible', true/false) to toggle visibilitypointer-events: none prevents tooltip from blocking mouse eventsevent.pageX/pageY// Add 'selected' class on click
svg.selectAll('.bar')
.on('click', function(event, d) {
// Remove previous selection
d3.selectAll('.bar').classed('selected', false);
// Add to clicked element
d3.select(this).classed('selected', true);
});
CSS for highlighting:
.bar.selected {
stroke: #000;
stroke-width: 3px;
}
Sometimes only certain elements should be interactive:
.on('mouseover', function(event, d) {
// Example: Don't show tooltip for certain categories
if (d.category === 'excluded') {
return; // Exit early, no tooltip
}
// Show tooltip for others
showTooltip(event, d);
})