--- name: d3-core-data description: Use when working with data transformations, scales, color schemes, formatting, or CSV/TSV parsing. Invoke for data processing pipelines, scale creation, color interpolation, number/date formatting, or data loading/parsing operations. allowed-tools: Read, Grep, Glob --- # D3 Core Data Expert ## Purpose Expert knowledge of D3's core data manipulation, transformation, and formatting capabilities. Covers data arrays, collections, scales, color schemes, number/date formatting, and CSV/TSV parsing. ## When to Use Invoke this skill when: - Processing or transforming data arrays (sorting, filtering, grouping) - Creating scales (linear, log, time, ordinal, band) - Working with color schemes and interpolation - Formatting numbers, dates, or currencies - Parsing CSV, TSV, or DSV files - Computing statistics (mean, median, extent, quantiles) - Creating data accessors and comparators - Building data processing pipelines - Debugging scale or formatting issues ## Documentation Available **Location**: `/Users/zach/Documents/cc-skills/docs/d3/` **Coverage** (385 files): - **Array Operations** (85 files): - Sorting, filtering, searching - Statistics: mean, median, sum, extent - Grouping, binning, histograms - Set operations, array utilities - **Collections** (33 files): - d3.group, d3.rollup, d3.index - Map, Set, InternMap utilities - Nested data structures - **Scales** (140 files): - Continuous: linear, log, pow, sqrt, symlog, time - Sequential: interpolation-based scales - Diverging: two-color scales - Quantize, quantile, threshold scales - Ordinal, band, point scales - Scale composition and inversion - **Colors** (49 files from scale-chromatic): - Categorical schemes (10+ palettes) - Sequential schemes (single-hue, multi-hue) - Diverging schemes (RdBu, PiYG, etc.) - Color interpolators - Color space conversions - **Color Module** (22 files): - RGB, HSL, Lab, HCL color spaces - Color parsing and manipulation - Color interpolation - **Formatting** (11 files): - Number formatting (d3-format) - Locale-aware formatting - SI prefixes, currencies - **Data Loading** (45 files total): - CSV/TSV parsing (d3-dsv: 33 files) - JSON, text fetching (d3-fetch: 12 files) - Auto-type conversion ## Related Skills - **d3-shapes-paths**: For using scales with line/area generators - **d3-geo**: For geographic scales and projections - **d3-layouts-hierarchies**: For hierarchical data structures - **d3-interaction-animation**: For animating scale transitions ## Best Practices - **Use scale domains from data** - Compute extent with d3.extent() - **Choose appropriate scale types** - Linear for continuous, band for categorical - **Normalize data ranges** - Use d3.normalize() or d3.scaleLinear() with [0, 1] range - **Use InternMap for keyed data** - Faster than native Map for string keys - **Apply color schemes consistently** - Use d3.schemeCategory10 for categorical data - **Format numbers for display** - d3.format() handles locales and SI prefixes - **Parse dates consistently** - Use d3.timeParse() with ISO format strings - **Handle missing data** - Use d3.mean(data, d => d.value) with accessor ## Examples ### Example 1: Data Processing Pipeline **Question**: "How do I process and group sales data by category?" **Response**: ```javascript import * as d3 from 'd3'; const salesData = [ { date: '2024-01-15', category: 'Electronics', amount: 1200 }, { date: '2024-01-16', category: 'Clothing', amount: 450 }, { date: '2024-01-16', category: 'Electronics', amount: 890 }, { date: '2024-01-17', category: 'Electronics', amount: 2100 }, { date: '2024-01-17', category: 'Clothing', amount: 680 }, ]; // Parse dates const parseTime = d3.timeParse('%Y-%m-%d'); salesData.forEach(d => { d.date = parseTime(d.date); d.amount = +d.amount; // Convert to number }); // Group by category and compute statistics const grouped = d3.rollup( salesData, v => ({ total: d3.sum(v, d => d.amount), mean: d3.mean(v, d => d.amount), count: v.length, }), d => d.category ); console.log(grouped); // Map(2) { // 'Electronics' => { total: 4190, mean: 1396.67, count: 3 }, // 'Clothing' => { total: 1130, mean: 565, count: 2 } // } // Sort by total descending const sorted = Array.from(grouped, ([key, value]) => ({ category: key, ...value })) .sort((a, b) => d3.descending(a.total, b.total)); console.log(sorted); // [ // { category: 'Electronics', total: 4190, mean: 1396.67, count: 3 }, // { category: 'Clothing', total: 1130, mean: 565, count: 2 } // ] ``` **Key Functions**: - `d3.rollup()` - Group and aggregate data - `d3.sum()`, `d3.mean()` - Compute statistics - `d3.descending()` - Sort comparator **References**: - See: `docs/d3/collection/` - See: `docs/d3/array/` ### Example 2: Creating and Using Scales **Question**: "How do I create scales for a scatter plot?" **Response**: ```javascript import * as d3 from 'd3'; const data = [ { x: 30, y: 20, size: 10, category: 'A' }, { x: 50, y: 80, size: 25, category: 'B' }, { x: 80, y: 50, size: 15, category: 'A' }, { x: 120, y: 90, size: 30, category: 'C' }, ]; // Create scales const xScale = d3.scaleLinear() .domain([0, d3.max(data, d => d.x)]) // [0, 120] .range([0, 800]) // SVG width .nice(); // Round to nice numbers const yScale = d3.scaleLinear() .domain(d3.extent(data, d => d.y)) // [20, 90] .range([400, 0]) // SVG height (inverted) .nice(); const sizeScale = d3.scaleSqrt() .domain([0, d3.max(data, d => d.size)]) .range([3, 20]); // Circle radius const colorScale = d3.scaleOrdinal() .domain(['A', 'B', 'C']) .range(d3.schemeCategory10); // Use scales data.forEach(d => { console.log({ x: xScale(d.x), // 200, 333, 533, 800 y: yScale(d.y), // 389, 29, 214, 0 r: sizeScale(d.size), // 8.2, 16.1, 11, 20 fill: colorScale(d.category), // Colors from scheme }); }); // Invert scale (e.g., for mouse position) const mouseX = 400; const dataX = xScale.invert(mouseX); // ~60 ``` **Scale Types**: - `scaleLinear()` - Continuous numeric mapping - `scaleSqrt()` - Square root scale (better for areas) - `scaleOrdinal()` - Categorical mapping - `scaleTime()` - For date/time domains **References**: - See: `docs/d3/scale/` - See: `docs/d3/scale-chromatic/` ### Example 3: Color Schemes **Question**: "How do I use D3 color schemes and interpolation?" **Response**: ```javascript import * as d3 from 'd3'; // Categorical colors (discrete) const categoricalColors = d3.schemeCategory10; console.log(categoricalColors); // Array of 10 colors const categoryScale = d3.scaleOrdinal() .domain(['apple', 'banana', 'cherry']) .range(d3.schemeSet2); // Sequential colors (continuous) const sequentialScale = d3.scaleSequential() .domain([0, 100]) .interpolator(d3.interpolateBlues); console.log(sequentialScale(0)); // Light blue console.log(sequentialScale(50)); // Medium blue console.log(sequentialScale(100)); // Dark blue // Diverging colors (continuous with midpoint) const divergingScale = d3.scaleDiverging() .domain([-10, 0, 10]) .interpolator(d3.interpolateRdYlGn); console.log(divergingScale(-10)); // Red console.log(divergingScale(0)); // Yellow console.log(divergingScale(10)); // Green // Custom color interpolation const colorInterpolator = d3.interpolateRgb('steelblue', 'brown'); console.log(colorInterpolator(0)); // steelblue console.log(colorInterpolator(0.5)); // middle color console.log(colorInterpolator(1)); // brown // Color manipulation const color = d3.rgb('steelblue'); console.log(color.brighter(1)); // Lighter console.log(color.darker(1)); // Darker console.log(color.opacity(0.5)); // With alpha // Convert between color spaces const lab = d3.lab('steelblue'); console.log(lab); // { l, a, b } ``` **Color Schemes Available**: - Categorical: Category10, Accent, Dark2, Set1, Set2, Set3 - Sequential: Blues, Greens, Reds, Oranges, Purples, Greys - Diverging: RdBu, RdYlGn, PiYG, BrBG, Spectral **References**: - See: `docs/d3/scale-chromatic/` - See: `docs/d3/color/` ### Example 4: Number and Date Formatting **Question**: "How do I format numbers and dates for display?" **Response**: ```javascript import * as d3 from 'd3'; // Number formatting const formatNumber = d3.format(','); // Thousands separator console.log(formatNumber(1234567)); // "1,234,567" const formatCurrency = d3.format('$,.2f'); // Currency with 2 decimals console.log(formatCurrency(1234.5)); // "$1,234.50" const formatPercent = d3.format('.1%'); // Percentage with 1 decimal console.log(formatPercent(0.1234)); // "12.3%" const formatSI = d3.format('.3s'); // SI prefix console.log(formatSI(1234567)); // "1.23M" console.log(formatSI(0.001234)); // "1.23m" const formatPrecision = d3.format('.2f'); // Fixed precision console.log(formatPrecision(Math.PI)); // "3.14" // Date formatting const formatTime = d3.timeFormat('%Y-%m-%d'); const date = new Date('2024-01-15T12:30:00'); console.log(formatTime(date)); // "2024-01-15" const formatDateTime = d3.timeFormat('%B %d, %Y at %I:%M %p'); console.log(formatDateTime(date)); // "January 15, 2024 at 12:30 PM" const formatShort = d3.timeFormat('%b %d'); console.log(formatShort(date)); // "Jan 15" // Parse dates const parseTime = d3.timeParse('%Y-%m-%d'); const parsed = parseTime('2024-01-15'); console.log(parsed); // Date object // Locale-specific formatting const frenchFormat = d3.formatLocale({ decimal: ',', thousands: '\u00a0', grouping: [3], currency: ['', '\u00a0€'], }); const formatEuro = frenchFormat.format('$,.2f'); console.log(formatEuro(1234.5)); // "1 234,50 €" ``` **Format Specifiers**: - `,` - Thousands separator - `.nf` - Fixed decimal places - `$` - Currency symbol - `%` - Multiply by 100 and add % - `.ns` - SI prefix (K, M, G, etc.) **References**: - See: `docs/d3/format/` - See: `docs/d3/time-format/` ### Example 5: CSV/TSV Data Loading **Question**: "How do I load and parse CSV data?" **Response**: ```javascript import * as d3 from 'd3'; // Load CSV from URL const data = await d3.csv('/data/sales.csv'); console.log(data); // [ // { date: '2024-01-15', sales: '1200', category: 'Electronics' }, // { date: '2024-01-16', sales: '450', category: 'Clothing' }, // ... // ] // Load with type conversion const typedData = await d3.csv('/data/sales.csv', d => ({ date: d3.timeParse('%Y-%m-%d')(d.date), sales: +d.sales, category: d.category, })); // Load with auto-type conversion const autoTyped = await d3.csv('/data/sales.csv', d3.autoType); // Load TSV (tab-separated) const tsvData = await d3.tsv('/data/sales.tsv'); // Load custom delimiter const customData = await d3.dsv('|', '/data/sales.txt'); // Parse CSV string const csvString = `date,sales,category 2024-01-15,1200,Electronics 2024-01-16,450,Clothing`; const parsed = d3.csvParse(csvString); console.log(parsed); // Parse with type conversion const typedParsed = d3.csvParse(csvString, d => ({ date: new Date(d.date), sales: +d.sales, category: d.category, })); // Format to CSV const output = d3.csvFormat(data); console.log(output); // date,sales,category // 2024-01-15,1200,Electronics // 2024-01-16,450,Clothing // Custom formatting const customOutput = d3.csvFormatRows([ ['date', 'sales', 'category'], ['2024-01-15', '1200', 'Electronics'], ]); ``` **Auto-type Conversions**: - Numbers: `"123"` → `123` - Booleans: `"true"` → `true` - Dates: `"2024-01-15"` → `Date` - `"NA"` or empty → `null` **References**: - See: `docs/d3/dsv/` - See: `docs/d3/fetch/` ## Common Patterns ### Compute Data Extent ```javascript const [min, max] = d3.extent(data, d => d.value); const domain = [0, max]; // Start from zero ``` ### Group Data by Multiple Keys ```javascript const grouped = d3.rollup( data, v => v.length, d => d.year, d => d.category ); // Map(year -> Map(category -> count)) ``` ### Create Histogram Bins ```javascript const histogram = d3.bin() .domain([0, 100]) .thresholds(10); // 10 bins const bins = histogram(data.map(d => d.value)); ``` ### Color Scale with Thresholds ```javascript const colorScale = d3.scaleThreshold() .domain([10, 20, 30]) .range(['green', 'yellow', 'orange', 'red']); ``` ### Time Scale for Dates ```javascript const timeScale = d3.scaleTime() .domain([new Date('2024-01-01'), new Date('2024-12-31')]) .range([0, 800]); ``` ## Search Helpers ```bash # Find scale documentation grep -r "scale\|domain\|range" /Users/zach/Documents/cc-skills/docs/d3/scale/ # Find color scheme docs grep -r "scheme\|interpolate\|color" /Users/zach/Documents/cc-skills/docs/d3/scale-chromatic/ # Find array operations grep -r "mean\|sum\|extent\|group" /Users/zach/Documents/cc-skills/docs/d3/array/ # Find formatting docs grep -r "format\|locale" /Users/zach/Documents/cc-skills/docs/d3/format/ # Find CSV parsing grep -r "csv\|tsv\|dsv\|parse" /Users/zach/Documents/cc-skills/docs/d3/dsv/ # List all data modules ls /Users/zach/Documents/cc-skills/docs/d3/ ``` ## Common Errors - **Scale domain is undefined**: Data hasn't loaded or accessor is wrong - Solution: Check d3.extent() returns valid [min, max] - **Colors not showing**: Wrong scale type for data - Solution: Use scaleOrdinal for categorical, scaleSequential for continuous - **Dates not parsing**: Format string doesn't match input - Solution: Match d3.timeParse() format to your date strings (e.g., '%Y-%m-%d') - **CSV numbers are strings**: No type conversion applied - Solution: Use d3.autoType or manual conversion with `+d.value` - **Scale inversion fails**: Can't invert ordinal scales - Solution: Only continuous scales support .invert() ## Performance Tips 1. **Use d3.InternMap** - Faster than native Map for string keys 2. **Avoid recomputing domains** - Cache extent calculations 3. **Use scale.copy()** - Clone scales instead of recreating 4. **Bin large datasets** - Use d3.bin() before rendering 5. **Parse dates once** - Don't re-parse in render loops 6. **Use d3.ticks()** - Generates nice axis values efficiently ## Notes - Documentation covers D3 v7 (latest version) - All scale types are immutable - methods return new scales - Color interpolation uses Lab color space by default (perceptually uniform) - d3.autoType handles most common CSV type conversions - InternMap is D3's optimized Map implementation - File paths reference local documentation cache - For latest updates, check https://d3js.org/d3-array