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:
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:
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:
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:
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:
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
const [min, max] = d3.extent(data, d => d.value);
const domain = [0, max]; // Start from zero
Group Data by Multiple Keys
const grouped = d3.rollup(
data,
v => v.length,
d => d.year,
d => d.category
);
// Map(year -> Map(category -> count))
Create Histogram Bins
const histogram = d3.bin()
.domain([0, 100])
.thresholds(10); // 10 bins
const bins = histogram(data.map(d => d.value));
Color Scale with Thresholds
const colorScale = d3.scaleThreshold()
.domain([10, 20, 30])
.range(['green', 'yellow', 'orange', 'red']);
Time Scale for Dates
const timeScale = d3.scaleTime()
.domain([new Date('2024-01-01'), new Date('2024-12-31')])
.range([0, 800]);
Search Helpers
# 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
- Use d3.InternMap - Faster than native Map for string keys
- Avoid recomputing domains - Cache extent calculations
- Use scale.copy() - Clone scales instead of recreating
- Bin large datasets - Use d3.bin() before rendering
- Parse dates once - Don't re-parse in render loops
- 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
1---2name: d3-core-data3description: 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.4---5
6# D3 Core Data Expert
7
8## Purpose
9
10Expert 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.
11
12## When to Use
13
14Invoke this skill when:
15- Processing or transforming data arrays (sorting, filtering, grouping)
16- Creating scales (linear, log, time, ordinal, band)
17- Working with color schemes and interpolation
18- Formatting numbers, dates, or currencies
19- Parsing CSV, TSV, or DSV files
20- Computing statistics (mean, median, extent, quantiles)
21- Creating data accessors and comparators
22- Building data processing pipelines
23- Debugging scale or formatting issues
24
25## Documentation Available
26
27**Location**: `/Users/zach/Documents/cc-skills/docs/d3/`
28
29**Coverage** (385 files):
30- **Array Operations** (85 files):
31 - Sorting, filtering, searching
32 - Statistics: mean, median, sum, extent
33 - Grouping, binning, histograms
34 - Set operations, array utilities
35
36- **Collections** (33 files):
37 - d3.group, d3.rollup, d3.index
38 - Map, Set, InternMap utilities
39 - Nested data structures
40
41- **Scales** (140 files):
42 - Continuous: linear, log, pow, sqrt, symlog, time
43 - Sequential: interpolation-based scales
44 - Diverging: two-color scales
45 - Quantize, quantile, threshold scales
46 - Ordinal, band, point scales
47 - Scale composition and inversion
48
49- **Colors** (49 files from scale-chromatic):
50 - Categorical schemes (10+ palettes)
51 - Sequential schemes (single-hue, multi-hue)
52 - Diverging schemes (RdBu, PiYG, etc.)
53 - Color interpolators
54 - Color space conversions
55
56- **Color Module** (22 files):
57 - RGB, HSL, Lab, HCL color spaces
58 - Color parsing and manipulation
59 - Color interpolation
60
61- **Formatting** (11 files):
62 - Number formatting (d3-format)
63 - Locale-aware formatting
64 - SI prefixes, currencies
65
66- **Data Loading** (45 files total):
67 - CSV/TSV parsing (d3-dsv: 33 files)
68 - JSON, text fetching (d3-fetch: 12 files)
69 - Auto-type conversion
70
71## Related Skills
72
73- **d3-shapes-paths**: For using scales with line/area generators
74- **d3-geo**: For geographic scales and projections
75- **d3-layouts-hierarchies**: For hierarchical data structures
76- **d3-interaction-animation**: For animating scale transitions
77
78## Best Practices
79
80- **Use scale domains from data** - Compute extent with d3.extent()
81- **Choose appropriate scale types** - Linear for continuous, band for categorical
82- **Normalize data ranges** - Use d3.normalize() or d3.scaleLinear() with [0, 1] range
83- **Use InternMap for keyed data** - Faster than native Map for string keys
84- **Apply color schemes consistently** - Use d3.schemeCategory10 for categorical data
85- **Format numbers for display** - d3.format() handles locales and SI prefixes
86- **Parse dates consistently** - Use d3.timeParse() with ISO format strings
87- **Handle missing data** - Use d3.mean(data, d => d.value) with accessor
88
89## Examples
90
91### Example 1: Data Processing Pipeline
92
93**Question**: "How do I process and group sales data by category?"
94
95**Response**:
96```javascript
97import * as d3 from 'd3';
98
99const salesData = [
100 { date: '2024-01-15', category: 'Electronics', amount: 1200 },
101 { date: '2024-01-16', category: 'Clothing', amount: 450 },
102 { date: '2024-01-16', category: 'Electronics', amount: 890 },
103 { date: '2024-01-17', category: 'Electronics', amount: 2100 },
104 { date: '2024-01-17', category: 'Clothing', amount: 680 },
105];
106
107// Parse dates
108const parseTime = d3.timeParse('%Y-%m-%d');
109salesData.forEach(d => {
110 d.date = parseTime(d.date);
111 d.amount = +d.amount; // Convert to number
112});
113
114// Group by category and compute statistics
115const grouped = d3.rollup(
116 salesData,
117 v => ({
118 total: d3.sum(v, d => d.amount),
119 mean: d3.mean(v, d => d.amount),
120 count: v.length,
121 }),
122 d => d.category
123);
124
125console.log(grouped);
126// Map(2) {
127// 'Electronics' => { total: 4190, mean: 1396.67, count: 3 },
128// 'Clothing' => { total: 1130, mean: 565, count: 2 }
129// }
130
131// Sort by total descending
132const sorted = Array.from(grouped, ([key, value]) => ({ category: key, ...value }))
133 .sort((a, b) => d3.descending(a.total, b.total));
134
135console.log(sorted);
136// [
137// { category: 'Electronics', total: 4190, mean: 1396.67, count: 3 },
138// { category: 'Clothing', total: 1130, mean: 565, count: 2 }
139// ]
140```
141
142**Key Functions**:
143- `d3.rollup()` - Group and aggregate data
144- `d3.sum()`, `d3.mean()` - Compute statistics
145- `d3.descending()` - Sort comparator
146
147**References**:
148- See: `docs/d3/collection/`
149- See: `docs/d3/array/`
150
151### Example 2: Creating and Using Scales
152
153**Question**: "How do I create scales for a scatter plot?"
154
155**Response**:
156```javascript
157import * as d3 from 'd3';
158
159const data = [
160 { x: 30, y: 20, size: 10, category: 'A' },
161 { x: 50, y: 80, size: 25, category: 'B' },
162 { x: 80, y: 50, size: 15, category: 'A' },
163 { x: 120, y: 90, size: 30, category: 'C' },
164];
165
166// Create scales
167const xScale = d3.scaleLinear()
168 .domain([0, d3.max(data, d => d.x)]) // [0, 120]
169 .range([0, 800]) // SVG width
170 .nice(); // Round to nice numbers
171
172const yScale = d3.scaleLinear()
173 .domain(d3.extent(data, d => d.y)) // [20, 90]
174 .range([400, 0]) // SVG height (inverted)
175 .nice();
176
177const sizeScale = d3.scaleSqrt()
178 .domain([0, d3.max(data, d => d.size)])
179 .range([3, 20]); // Circle radius
180
181const colorScale = d3.scaleOrdinal()
182 .domain(['A', 'B', 'C'])
183 .range(d3.schemeCategory10);
184
185// Use scales
186data.forEach(d => {
187 console.log({
188 x: xScale(d.x), // 200, 333, 533, 800
189 y: yScale(d.y), // 389, 29, 214, 0
190 r: sizeScale(d.size), // 8.2, 16.1, 11, 20
191 fill: colorScale(d.category), // Colors from scheme
192 });
193});
194
195// Invert scale (e.g., for mouse position)
196const mouseX = 400;
197const dataX = xScale.invert(mouseX); // ~60
198```
199
200**Scale Types**:
201- `scaleLinear()` - Continuous numeric mapping
202- `scaleSqrt()` - Square root scale (better for areas)
203- `scaleOrdinal()` - Categorical mapping
204- `scaleTime()` - For date/time domains
205
206**References**:
207- See: `docs/d3/scale/`
208- See: `docs/d3/scale-chromatic/`
209
210### Example 3: Color Schemes
211
212**Question**: "How do I use D3 color schemes and interpolation?"
213
214**Response**:
215```javascript
216import * as d3 from 'd3';
217
218// Categorical colors (discrete)
219const categoricalColors = d3.schemeCategory10;
220console.log(categoricalColors); // Array of 10 colors
221
222const categoryScale = d3.scaleOrdinal()
223 .domain(['apple', 'banana', 'cherry'])
224 .range(d3.schemeSet2);
225
226// Sequential colors (continuous)
227const sequentialScale = d3.scaleSequential()
228 .domain([0, 100])
229 .interpolator(d3.interpolateBlues);
230
231console.log(sequentialScale(0)); // Light blue
232console.log(sequentialScale(50)); // Medium blue
233console.log(sequentialScale(100)); // Dark blue
234
235// Diverging colors (continuous with midpoint)
236const divergingScale = d3.scaleDiverging()
237 .domain([-10, 0, 10])
238 .interpolator(d3.interpolateRdYlGn);
239
240console.log(divergingScale(-10)); // Red
241console.log(divergingScale(0)); // Yellow
242console.log(divergingScale(10)); // Green
243
244// Custom color interpolation
245const colorInterpolator = d3.interpolateRgb('steelblue', 'brown');
246console.log(colorInterpolator(0)); // steelblue
247console.log(colorInterpolator(0.5)); // middle color
248console.log(colorInterpolator(1)); // brown
249
250// Color manipulation
251const color = d3.rgb('steelblue');
252console.log(color.brighter(1)); // Lighter
253console.log(color.darker(1)); // Darker
254console.log(color.opacity(0.5)); // With alpha
255
256// Convert between color spaces
257const lab = d3.lab('steelblue');
258console.log(lab); // { l, a, b }
259```
260
261**Color Schemes Available**:
262- Categorical: Category10, Accent, Dark2, Set1, Set2, Set3
263- Sequential: Blues, Greens, Reds, Oranges, Purples, Greys
264- Diverging: RdBu, RdYlGn, PiYG, BrBG, Spectral
265
266**References**:
267- See: `docs/d3/scale-chromatic/`
268- See: `docs/d3/color/`
269
270### Example 4: Number and Date Formatting
271
272**Question**: "How do I format numbers and dates for display?"
273
274**Response**:
275```javascript
276import * as d3 from 'd3';
277
278// Number formatting
279const formatNumber = d3.format(','); // Thousands separator
280console.log(formatNumber(1234567)); // "1,234,567"
281
282const formatCurrency = d3.format('$,.2f'); // Currency with 2 decimals
283console.log(formatCurrency(1234.5)); // "$1,234.50"
284
285const formatPercent = d3.format('.1%'); // Percentage with 1 decimal
286console.log(formatPercent(0.1234)); // "12.3%"
287
288const formatSI = d3.format('.3s'); // SI prefix
289console.log(formatSI(1234567)); // "1.23M"
290console.log(formatSI(0.001234)); // "1.23m"
291
292const formatPrecision = d3.format('.2f'); // Fixed precision
293console.log(formatPrecision(Math.PI)); // "3.14"
294
295// Date formatting
296const formatTime = d3.timeFormat('%Y-%m-%d');
297const date = new Date('2024-01-15T12:30:00');
298console.log(formatTime(date)); // "2024-01-15"
299
300const formatDateTime = d3.timeFormat('%B %d, %Y at %I:%M %p');
301console.log(formatDateTime(date)); // "January 15, 2024 at 12:30 PM"
302
303const formatShort = d3.timeFormat('%b %d');
304console.log(formatShort(date)); // "Jan 15"
305
306// Parse dates
307const parseTime = d3.timeParse('%Y-%m-%d');
308const parsed = parseTime('2024-01-15');
309console.log(parsed); // Date object
310
311// Locale-specific formatting
312const frenchFormat = d3.formatLocale({
313 decimal: ',',
314 thousands: '\u00a0',
315 grouping: [3],
316 currency: ['', '\u00a0€'],
317});
318
319const formatEuro = frenchFormat.format('$,.2f');
320console.log(formatEuro(1234.5)); // "1 234,50 €"
321```
322
323**Format Specifiers**:
324- `,` - Thousands separator
325- `.nf` - Fixed decimal places
326- `$` - Currency symbol
327- `%` - Multiply by 100 and add %
328- `.ns` - SI prefix (K, M, G, etc.)
329
330**References**:
331- See: `docs/d3/format/`
332- See: `docs/d3/time-format/`
333
334### Example 5: CSV/TSV Data Loading
335
336**Question**: "How do I load and parse CSV data?"
337
338**Response**:
339```javascript
340import * as d3 from 'd3';
341
342// Load CSV from URL
343const data = await d3.csv('/data/sales.csv');
344console.log(data);
345// [
346// { date: '2024-01-15', sales: '1200', category: 'Electronics' },
347// { date: '2024-01-16', sales: '450', category: 'Clothing' },
348// ...
349// ]
350
351// Load with type conversion
352const typedData = await d3.csv('/data/sales.csv', d => ({
353 date: d3.timeParse('%Y-%m-%d')(d.date),
354 sales: +d.sales,
355 category: d.category,
356}));
357
358// Load with auto-type conversion
359const autoTyped = await d3.csv('/data/sales.csv', d3.autoType);
360
361// Load TSV (tab-separated)
362const tsvData = await d3.tsv('/data/sales.tsv');
363
364// Load custom delimiter
365const customData = await d3.dsv('|', '/data/sales.txt');
366
367// Parse CSV string
368const csvString = `date,sales,category
3692024-01-15,1200,Electronics
3702024-01-16,450,Clothing`;
371
372const parsed = d3.csvParse(csvString);
373console.log(parsed);
374
375// Parse with type conversion
376const typedParsed = d3.csvParse(csvString, d => ({
377 date: new Date(d.date),
378 sales: +d.sales,
379 category: d.category,
380}));
381
382// Format to CSV
383const output = d3.csvFormat(data);
384console.log(output);
385// date,sales,category
386// 2024-01-15,1200,Electronics
387// 2024-01-16,450,Clothing
388
389// Custom formatting
390const customOutput = d3.csvFormatRows([
391 ['date', 'sales', 'category'],
392 ['2024-01-15', '1200', 'Electronics'],
393]);
394```
395
396**Auto-type Conversions**:
397- Numbers: `"123"` → `123`
398- Booleans: `"true"` → `true`
399- Dates: `"2024-01-15"` → `Date`
400- `"NA"` or empty → `null`
401
402**References**:
403- See: `docs/d3/dsv/`
404- See: `docs/d3/fetch/`
405
406## Common Patterns
407
408### Compute Data Extent
409```javascript
410const [min, max] = d3.extent(data, d => d.value);
411const domain = [0, max]; // Start from zero
412```
413
414### Group Data by Multiple Keys
415```javascript
416const grouped = d3.rollup(
417 data,
418 v => v.length,
419 d => d.year,
420 d => d.category
421);
422// Map(year -> Map(category -> count))
423```
424
425### Create Histogram Bins
426```javascript
427const histogram = d3.bin()
428 .domain([0, 100])
429 .thresholds(10); // 10 bins
430
431const bins = histogram(data.map(d => d.value));
432```
433
434### Color Scale with Thresholds
435```javascript
436const colorScale = d3.scaleThreshold()
437 .domain([10, 20, 30])
438 .range(['green', 'yellow', 'orange', 'red']);
439```
440
441### Time Scale for Dates
442```javascript
443const timeScale = d3.scaleTime()
444 .domain([new Date('2024-01-01'), new Date('2024-12-31')])
445 .range([0, 800]);
446```
447
448## Search Helpers
449
450```bash
451# Find scale documentation
452grep -r "scale\|domain\|range" /Users/zach/Documents/cc-skills/docs/d3/scale/
453
454# Find color scheme docs
455grep -r "scheme\|interpolate\|color" /Users/zach/Documents/cc-skills/docs/d3/scale-chromatic/
456
457# Find array operations
458grep -r "mean\|sum\|extent\|group" /Users/zach/Documents/cc-skills/docs/d3/array/
459
460# Find formatting docs
461grep -r "format\|locale" /Users/zach/Documents/cc-skills/docs/d3/format/
462
463# Find CSV parsing
464grep -r "csv\|tsv\|dsv\|parse" /Users/zach/Documents/cc-skills/docs/d3/dsv/
465
466# List all data modules
467ls /Users/zach/Documents/cc-skills/docs/d3/
468```
469
470## Common Errors
471
472- **Scale domain is undefined**: Data hasn't loaded or accessor is wrong
473 - Solution: Check d3.extent() returns valid [min, max]
474
475- **Colors not showing**: Wrong scale type for data
476 - Solution: Use scaleOrdinal for categorical, scaleSequential for continuous
477
478- **Dates not parsing**: Format string doesn't match input
479 - Solution: Match d3.timeParse() format to your date strings (e.g., '%Y-%m-%d')
480
481- **CSV numbers are strings**: No type conversion applied
482 - Solution: Use d3.autoType or manual conversion with `+d.value`
483
484- **Scale inversion fails**: Can't invert ordinal scales
485 - Solution: Only continuous scales support .invert()
486
487## Performance Tips
488
4891. **Use d3.InternMap** - Faster than native Map for string keys
4902. **Avoid recomputing domains** - Cache extent calculations
4913. **Use scale.copy()** - Clone scales instead of recreating
4924. **Bin large datasets** - Use d3.bin() before rendering
4935. **Parse dates once** - Don't re-parse in render loops
4946. **Use d3.ticks()** - Generates nice axis values efficiently
495
496## Notes
497
498- Documentation covers D3 v7 (latest version)
499- All scale types are immutable - methods return new scales
500- Color interpolation uses Lab color space by default (perceptually uniform)
501- d3.autoType handles most common CSV type conversions
502- InternMap is D3's optimized Map implementation
503- File paths reference local documentation cache
504- For latest updates, check https://d3js.org/d3-array