Работа с данными в D3.js начинается задолго до построения визуализации. Этап загрузки и преобразования формирует структуру, с которой далее взаимодействуют масштабы, оси, генераторы форм и компоненты визуализации. Ошибки на этом этапе проявляются позже — в некорректных шкалах, смещённых точках, сломанных агрегациях.
D3 рассматривает данные как типизированные структуры JavaScript, но исходные источники почти всегда предоставляют строки: CSV, TSV, JSON с текстовыми полями, API-ответы с нестрогой типизацией. Поэтому ключевая задача загрузки — не просто чтение, а приведение типов и нормализация структуры.
В D3 используется модуль загрузки данных (d3-fetch), где
основными функциями выступают:
d3.csvd3.tsvd3.jsond3.textd3.xmlКаждая функция возвращает Promise, а обработка данных
происходит в цепочке .then().
CSV-файлы изначально не содержат типов. Например:
year,price,count,date
2020,12.5,10,2020-01-01
После загрузки:
year → строка "2020"price → строка "12.5"count → строка "10"date → строка "2020-01-01"Без дополнительной обработки любые числовые и временные операции будут некорректны.
D3 предоставляет встроенный механизм автоматического определения
типов — d3.autoType.
Он применяется как функция преобразования строк в:
Пример использования:
d3.csv("data.csv", d3.autoType).then(data => {
console.log(data);
});
Алгоритм анализа значений:
"42" → 42"3.14" → 3.14"true" → true"false" → false"2020-01-01" → Date"" → nullОднако автоматизм имеет ограничения:
"1,000") не
обрабатываютсяНаиболее надёжный способ контроля типов — функция преобразования строки при загрузке.
d3.csv("data.csv", function(row) {
return {
year: +row.year,
price: parseFloat(row.price),
count: parseInt(row.count, 10),
date: new Date(row.date)
};
}).then(data => {
console.log(data);
});
value: +row.value
Особенности:
parseFloatNaN при ошибкеparseInt("10px", 10) // 10
parseFloat("10.5kg") // 10.5
Проблема: частичное чтение строки может скрывать ошибки данных.
new Date("2020-01-01")
Работает только с ISO-форматом и близкими к нему строками.
Когда данные приходят в виде:
01/2020
2020-01
используется d3.timeParse:
const parseDate = d3.timeParse("%m/%Y");
d3.csv("data.csv", row => ({
date: parseDate(row.date),
value: +row.value
}));
Форматирование основано на спецификаторах:
%Y — год%m — месяц%d — день%H — час%M — минутаВ европейских форматах числа могут выглядеть так:
1.234,56
Стандартный JavaScript не интерпретирует такие значения корректно.
D3 решает проблему через локализованные парсеры:
const locale = d3.formatLocale({
decimal: ",",
thousands: ".",
grouping: [3],
currency: ["", ""]
});
const parseNumber = locale.numberParse(",");
Применение:
value: parseNumber(row.value)
D3 нормализует отсутствие данных, но поведение зависит от метода загрузки:
null (при autoType)undefined"NA", "-" → остаются строками без
кастомной обработкиПрактический подход:
value: row.value === "NA" ? null : +row.value
Типизация часто совмещается с проверкой:
d3.csv("data.csv", row => {
const value = +row.value;
if (!Number.isFinite(value)) {
return null;
}
return {
id: row.id,
value
};
}).then(data => {
data = data.filter(d => d !== null);
});
CSV и JSON API часто приходят в несовместимых формах.
Исходные данные:
{
"id": "A1",
"metrics": {
"value": "10",
"time": "2020-01-01"
}
}
Преобразование:
d3.json("data.json").then(data => {
return data.map(d => ({
id: d.id,
value: +d.metrics.value,
time: new Date(d.metrics.time)
}));
});
Типичный pipeline:
d3.csv, d3.json)Пример:
d3.csv("data.csv", d3.autoType)
.then(data => data.filter(d => d.value > 0))
.then(data => d3.group(data, d => d.category))
.then(grouped => {
console.log(grouped);
});
"2020-13-01" → invalid Date
Результат: Invalid Date без исключения.
Строки:
"00123"
Могут быть интерпретированы как число 123, что критично
для идентификаторов.
+"" // 0
+"abc" // NaN
NaN легко распространяется по вычислениям и ломает масштабы.
Идентификаторы часто ошибочно преобразуются в числа.
Правильная стратегия:
id строкойd3.csv("data.csv", row => ({
id: row.id,
value: +row.value
}));
При больших CSV-файлах важна минимизация операций:
Пример оптимизированного подхода:
d3.csv("large.csv", row => ({
x: +row.x,
y: +row.y
}));
Часто данные сразу дополняются производными значениями:
d3.csv("data.csv", row => {
const value = +row.value;
return {
value,
logValue: Math.log(value),
category: value > 10 ? "high" : "low"
};
});
Такой подход снижает нагрузку на этап визуализации и переносит вычисления в фазу подготовки данных.
Корректная типизация данных влияет на:
d3.scaleLinear,
d3.scaleTime)d3.axisBottom)d3.rollup, d3.group)Ошибки типов на входе приводят к каскадным сбоям визуальных компонентов, поскольку D3 не выполняет строгую типовую проверку на уровне графических примитивов.