Как заменить гнездовую функцию d3js на group и rollup

#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}}
     )