CSV Data Handling with D3.js
SkillFiles & storageLoading and parsing CSV files with D3.js, data transformation, and handling missing values
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the CSV Data Handling with D3.js skill
What this skill tells your AI
The instructions your AI receives, as published by cxcscmu/skilllearnbench in skills/b1-one-shot-claude-haiku-4-5/stock-data-visualization/csv-data-handling/SKILL.md and read by ahel’s review.
Overview
D3.js provides built-in CSV parsing. Understanding type coercion and data transformation is essential for visualization.
1. Loading CSV Files
Basic CSV Load
d3.csv("data.csv").then(data => {
console.log(data); // Array of objects
// [{ key1: value1, key2: value2 }, ...]
});
With Error Handling
d3.csv("data.csv")
.then(data => {
console.log("Data loaded:", data.length, "rows");
processData(data);
})
.catch(error => {
console.error("Error loading CSV:", error);
});
With Type Accessor
D3 can automatically convert types:
d3.csv("data.csv", row => {
return {
ticker: row.ticker,
marketCap: +row.marketCap, // convert to number
sector: row.sector,
value: parseFloat(row.value)
};
}).then(processData);
2. Data Transformation
Parsing Numeric Values
data.forEach(d => {
d.marketCap = +d.marketCap; // unary + operator
d.employees = parseInt(d.employees, 10);
d.yield = parseFloat(d.yield);
});
Handling Missing Values
data = data.filter(d => {
// Keep only rows with required data
return d.marketCap && d.sector;
});
// Or replace missing with default
data.forEach(d => {
d.marketCap = d.marketCap || 0;
d.website = d.website || "N/A";
});
Filtering and Sorting
// Filter by sector
const tech = data.filter(d => d.sector === "Information Technology");
// Sort by market cap
data.sort((a, b) => b.marketCap - a.marketCap);
// Top 50 by market cap
const top50 = data.sort((a, b) => b.marketCap - a.marketCap).slice(0, 50);
3. Loading Multiple Files
Sequential Loading
Promise.all([
d3.csv("companies.csv"),
d3.csv("prices.csv")
]).then(([companies, prices]) => {
// Both loaded
const merged = mergeData(companies, prices);
visualize(merged);
});
Loading Individual Stock Data
// Load main data
d3.csv("data/stock-descriptions.csv").then(stocks => {
// For each stock, load price history
const pricePromises = stocks.map(stock =>
d3.csv(`data/indiv-stock/${stock.ticker}.csv`)
.then(prices => ({
ticker: stock.ticker,
prices: prices
}))
);
return Promise.all(pricePromises);
}).then(allData => {
// Process combined data
visualize(allData);
});
4. Aggregation & Grouping
Group by Category
const bySetor = d3.group(data, d => d.sector);
// Map { sector: [stocks...], ... }
// Or convert to array
const sectorGroups = Array.from(bySetor, ([sector, stocks]) => ({
sector,
count: stocks.length,
totalCap: d3.sum(stocks, d => d.marketCap)
}));
Nesting (Hierarchical Grouping)
const nested = d3.nest()
.key(d => d.sector)
.entries(data);
// Returns: [{ key: "sector1", values: [stocks...] }, ...]
5. Formatting Numbers for Display
Format for Visualization
// Market cap formatter
const capFormatter = d3.format(".2s"); // "1.6T"
const capFormat = (value) => {
const sizes = ['', 'K', 'M', 'B', 'T'];
let sizeIndex = 0;
let num = value;
while (num >= 1000 && sizeIndex < sizes.length - 1) {
num /= 1000;
sizeIndex++;
}
return num.toFixed(2) + sizes[sizeIndex];
};
console.log(capFormat(1641026945024)); // "1.64T"
Format Percentages
const percentFormatter = d3.format(".2%");
console.log(percentFormatter(0.28806)); // "28.81%"
6. Data Validation
Check for Required Fields
function validateData(data) {
return data.every(d => {
return d.ticker &&
d.sector &&
d.marketCap !== undefined;
});
}
if (!validateData(data)) {
console.error("Invalid data structure");
}
7. Copying Data for Performance
Deep Copy to Avoid Mutations
// Shallow copy (references still point to original objects)
const copy1 = [...data];
const copy2 = data.slice();
// Deep copy (complete independence)
const copy3 = JSON.parse(JSON.stringify(data));
// Selective copy
const lightweightData = data.map(d => ({
ticker: d.ticker,
sector: d.sector,
marketCap: d.marketCap
}));
Common Patterns
Parse and Enrich
d3.csv("stocks.csv")
.then(stocks => {
// Type conversion
stocks.forEach(d => {
d.marketCap = +d.marketCap;
d.employees = +d.employees;
});
// Filter out invalid
stocks = stocks.filter(d => d.marketCap > 0);
// Add computed fields
stocks.forEach(d => {
d.capFormatted = capFormatter(d.marketCap);
d.category = categorizeByMarketCap(d.marketCap);
});
return stocks;
})
.then(processedData => visualize(processedData));
Tips & Gotchas
- CSV string "1000000" stays a string until converted
- Empty cells become empty strings "", not null
- Use
d => d.valueto access object properties, notd["value"] - D3's CSV parser handles quoted fields with commas automatically
- Use
Promise.all()for loading multiple files in parallel - Always validate data structure before visualizing
Signals
- GitHub stars
- 83
- Forks
- 5
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
csv-data-handling- Source
- github.com/cxcscmu/skilllearnbench