#javascript #d3.js #data-structures
#javascript #d3.js #структуры данных
Вопрос:
Я изо всех сил пытаюсь перевести какой-то старый код d3js в новейшую версию (V6). Похоже, старая функция nest()
устарела. С этого момента документы рекомендуют использовать group()
, и rollup()
, однако, они не дают никаких реальных хороших примеров, и я изо всех сил пытаюсь достичь той же структуры данных с помощью этих новых функций.
Ввод данных:
[
{
name: "Anton",
year: "1990"
},
{
name: "Anton",
year: "1990"
},
{
name: "Anton",
year: "1971"
},
{
name: "Markus",
year: "1981"
},
]
Старый код D3:
let nested = d3.nest()
.key(function (d) { return d.name })
.key(function (d) { return d.year })
.rollup(function (leaves) { return leaves.length })
.entries(data)
Вывод (правильный):
[
{
key: "Anton"
values: [
{
key: "1990",
value: 2
}
{
key: "1971",
value: 1
}
]
},
{
key: "Markus"
values: [
key: "1981"
value: 1
]
}
]
Новый код
Я пытался комбинировать group
и rollup
по-разному, но всегда получаю другую структуру данных. Закрытие, к которому я пришел, заключается в следующем:
let rollup = d3.rollups(data, v => v.length, d => d.name, d => d.year);
let arrayFromRollup = Array.from(rollup, ([key, value]) => ({key, value}));
Вывод (неверный)
[
{
key: "Anton"
values: [
["1990", 2],
["1971", 1]
]
},
{
key: "Markus"
values: [
["1981", 1]
]
}
]
Я полезен для любых советов, по-видимому, большинство похожих вопросов / сообщений, которые я нашел, довольно старые и работают nest
.
Ответ №1:
D3 предоставляет отличные удобные функции, но с появлением ES6 манипулирование массивами и объектами стало намного проще. Вы можете добиться этого, используя чистые методы ES6:
const input = [{
name: "Anton",
year: "1990"
},
{
name: "Anton",
year: "1990"
},
{
name: "Anton",
year: "1971"
},
{
name: "Markus",
year: "1981"
},
]
const expected = [
{
key: "Anton",
values: [
{
key: "1990",
value: 2
},
{
key: "1971",
value: 1
}
],
},
{
key: "Markus",
values: [
{
key: "1981",
value: 1,
}
],
},
];
// For ease of use, start with an object, we map key to values
// and unpack it later. The structure we go for now:
// { name: { year: count }}
const nameYearsCount = input.reduce((obj, {
name,
year
}) => {
if (!(name in obj)) {
obj[name] = {
[year]: 1
};
} else {
// I.e. if the year doesn't exist, default to zero
obj[name][year] = (obj[name][year] || 0) 1
}
return obj;
}, {});
// Now transform it into the desired format
const result = Object.entries(nameYearsCount)
.map(([name, yearsCount]) => {
const values = Object.entries(yearsCount)
.map(([year, count]) => ({
key: year,
value: count
}));
return {
key: name,
values
};
});
console.log(result);
Комментарии:
1. Спасибо! Это работает. Однако жаль, что в D3 нет лучшей документации по переходу между разными версиями.
2. Вот почему это основная проблема с версией, поэтому они могут изменить даже базовый API
3. Верно, но руководство все равно было бы неплохо.
4. В примечаниях к выпуску часто есть руководства, подобные этому
Ответ №2:
Вот хорошая документация по group и rollup: https://observablehq.com/@d3/d3-group
Поместите следующее в наблюдаемое в качестве примера:
d3.rollup(athletes,
v => {return {values: {len: v.length, earn:d3.sum(v, d => d.earnings)}}; },
d => {return {key: d.nation}},
d => {return {key: d.sport}}
)