From Web Publishing
Creates D3.js charts, graphs, and interactive data visualizations with templates for bar charts, line charts, and more.
How this skill is triggered — by the user, by Claude, or both
Slash command
/web-publish:d3-visualizationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Создание интерактивных визуализаций данных с D3.js: графики, диаграммы, карты.
Создание интерактивных визуализаций данных с D3.js: графики, диаграммы, карты.
<!-- CDN -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- Or npm -->
<!-- npm install d3 -->
// Selection
d3.select("#chart") // Single element
d3.selectAll(".bar") // Multiple elements
// Data binding
const data = [10, 20, 30, 40, 50];
d3.select("#chart")
.selectAll("rect")
.data(data)
.join("rect")
.attr("height", d => d)
.attr("width", 20);
// Scales
const xScale = d3.scaleLinear()
.domain([0, 100]) // Input range
.range([0, 500]); // Output range
const colorScale = d3.scaleOrdinal()
.domain(["A", "B", "C"])
.range(["red", "green", "blue"]);
function barChart(data, selector) {
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
// Clear previous
d3.select(selector).html("");
// SVG container
const svg = d3.select(selector)
.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 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));
// Bars
svg.selectAll(".bar")
.data(data)
.join("rect")
.attr("class", "bar")
.attr("x", d => x(d.label))
.attr("y", d => y(d.value))
.attr("width", x.bandwidth())
.attr("height", d => height - y(d.value))
.attr("fill", "steelblue")
.on("mouseover", function() {
d3.select(this).attr("fill", "orange");
})
.on("mouseout", function() {
d3.select(this).attr("fill", "steelblue");
});
}
// Usage
const data = [
{ label: "A", value: 30 },
{ label: "B", value: 80 },
{ label: "C", value: 45 },
{ label: "D", value: 60 },
{ label: "E", value: 20 }
];
barChart(data, "#chart");
function lineChart(data, selector) {
const margin = { top: 20, right: 30, bottom: 30, left: 50 };
const width = 600 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
d3.select(selector).html("");
const svg = d3.select(selector)
.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})`);
// Parse dates if needed
const parseDate = d3.timeParse("%Y-%m-%d");
data.forEach(d => {
d.date = parseDate(d.date);
});
// Scales
const x = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([0, width]);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.nice()
.range([height, 0]);
// Line generator
const line = d3.line()
.x(d => x(d.date))
.y(d => y(d.value))
.curve(d3.curveMonotoneX);
// Axes
svg.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x).ticks(6));
svg.append("g")
.call(d3.axisLeft(y));
// Line path
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-width", 2)
.attr("d", line);
// Dots
svg.selectAll(".dot")
.data(data)
.join("circle")
.attr("class", "dot")
.attr("cx", d => x(d.date))
.attr("cy", d => y(d.value))
.attr("r", 4)
.attr("fill", "steelblue");
}
function pieChart(data, selector) {
const width = 400;
const height = 400;
const radius = Math.min(width, height) / 2;
d3.select(selector).html("");
const svg = d3.select(selector)
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", `translate(${width/2},${height/2})`);
// Color scale
const color = d3.scaleOrdinal()
.domain(data.map(d => d.label))
.range(d3.schemeCategory10);
// Pie generator
const pie = d3.pie()
.value(d => d.value)
.sort(null);
// Arc generator
const arc = d3.arc()
.innerRadius(0)
.outerRadius(radius - 10);
const arcHover = d3.arc()
.innerRadius(0)
.outerRadius(radius);
// Draw slices
svg.selectAll("path")
.data(pie(data))
.join("path")
.attr("d", arc)
.attr("fill", d => color(d.data.label))
.attr("stroke", "white")
.attr("stroke-width", 2)
.on("mouseover", function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr("d", arcHover);
})
.on("mouseout", function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr("d", arc);
});
// Labels
svg.selectAll("text")
.data(pie(data))
.join("text")
.attr("transform", d => `translate(${arc.centroid(d)})`)
.attr("text-anchor", "middle")
.text(d => d.data.label)
.style("font-size", "12px")
.style("fill", "white");
}
function donutChart(data, selector) {
const width = 400;
const height = 400;
const radius = Math.min(width, height) / 2;
const innerRadius = radius * 0.6; // Donut hole
// ... same as pie but with:
const arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(radius - 10);
// Center text
svg.append("text")
.attr("text-anchor", "middle")
.attr("dy", "0.35em")
.style("font-size", "24px")
.text(d3.sum(data, d => d.value));
}
// Create tooltip div
const tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("position", "absolute")
.style("visibility", "hidden")
.style("background", "rgba(0,0,0,0.8)")
.style("color", "white")
.style("padding", "8px")
.style("border-radius", "4px");
// Add to elements
svg.selectAll("rect")
.on("mouseover", function(event, d) {
tooltip
.style("visibility", "visible")
.html(`<strong>${d.label}</strong><br>Value: ${d.value}`);
})
.on("mousemove", function(event) {
tooltip
.style("top", (event.pageY - 10) + "px")
.style("left", (event.pageX + 10) + "px");
})
.on("mouseout", function() {
tooltip.style("visibility", "hidden");
});
const zoom = d3.zoom()
.scaleExtent([0.5, 5])
.on("zoom", (event) => {
svg.attr("transform", event.transform);
});
d3.select("svg").call(zoom);
// Animate bars
svg.selectAll(".bar")
.data(newData)
.transition()
.duration(750)
.attr("y", d => y(d.value))
.attr("height", d => height - y(d.value));
// Animate line
path
.transition()
.duration(1000)
.attrTween("stroke-dasharray", function() {
const length = this.getTotalLength();
return d3.interpolate(`0,${length}`, `${length},${length}`);
});
function responsiveChart(selector) {
const container = d3.select(selector);
function render() {
const width = container.node().getBoundingClientRect().width;
const height = width * 0.6;
container.html("");
const svg = container
.append("svg")
.attr("width", width)
.attr("height", height);
// ... draw chart with calculated dimensions
}
render();
// Resize handler
d3.select(window).on("resize", () => {
render();
});
}
// Linear (continuous numbers)
d3.scaleLinear().domain([0, 100]).range([0, 500])
// Time
d3.scaleTime().domain([startDate, endDate]).range([0, width])
// Ordinal (categories)
d3.scaleOrdinal().domain(["A", "B", "C"]).range(["red", "green", "blue"])
// Band (for bar charts)
d3.scaleBand().domain(categories).range([0, width]).padding(0.1)
// Log
d3.scaleLog().domain([1, 1000]).range([0, 500])
// Sqrt
d3.scaleSqrt().domain([0, 100]).range([0, 20]) // For bubble sizes
// Built-in schemes
d3.schemeCategory10 // 10 colors
d3.schemeTableau10 // Tableau colors
d3.schemePaired // 12 paired colors
d3.schemeSet3 // 12 pastel colors
// Sequential
d3.interpolateBlues // Light to dark blue
d3.interpolateViridis // Purple-yellow
d3.interpolateRdYlGn // Red-yellow-green
// Usage with scale
const colorScale = d3.scaleSequential()
.domain([0, 100])
.interpolator(d3.interpolateViridis);
// Group data
const grouped = d3.group(data, d => d.category);
// Rollup (aggregate)
const totals = d3.rollup(data,
v => d3.sum(v, d => d.value),
d => d.category
);
// Stack (for stacked charts)
const stack = d3.stack()
.keys(["A", "B", "C"]);
const stackedData = stack(data);
// Bin (histogram)
const bins = d3.bin()
.domain([0, 100])
.thresholds(10)
(data);
Mines projects and conversations into a searchable memory palace. Activates on queries about MemPalace, memory palace, mining, searching, palace setup, wings, rooms, drawers, or recalling past work.
Guides Payload CMS config (payload.config.ts), collections, fields, hooks, access control, APIs. Debugs validation errors, security, relationships, queries, transactions, hook behavior.
Implements vector databases with Pinecone, Weaviate, Qdrant, Milvus, pgvector for semantic search, RAG, recommendations, and similarity systems. Optimizes embeddings, indexing, and hybrid search.
npx claudepluginhub jhamidun/claude-code-config-pack --plugin web-publish