D3.nest() и преобразование значений в имя и для детей

Я работаю над созданием Treemap из CSV файла. Данные в файле CSV являются иерархическими, в результате я использовал d3.nest().

Однако полученный JSON имеет вид {key:"United States", values:[...]}. Для дерева с возможностью масштабирования требуется иерархия {name:"United States", children:[...]}. Я попытался заменить имя и дочерние элементы на ключ и значения в примере, но это не работает.

Если кто-то уже изучил использование ключа и значений на масштабируемой древовидной карте, пожалуйста, помогите. Я новичок в D3, и я не знаю, означает ли d.children структуру или значение из данных.

Это код для преобразования мировых континентов, регионов и стран из CSV в иерархию с использованием d3.

$ d3.csv("../Data/WorldPopulation.csv", function (pop) {
    var treeData= { "key": "World", "values": d3.nest()
   .key(function (d) { return d.Major_Region; })
   .key(function (d) { return d.Region; })
   .key(function (d) { return d.Country; })
   .entries(pop)
};

Первые несколько строк результата:

 '[{"key":"AFRICA","values":[{"key":"Eastern Africa","values"
 [{"key":"Burundi","values":[.........'

Я не могу использовать масштабируемую древовидную карту, потому что она требует имен и дочерних меток в json, а не ключа и значений.

Ответ 1

Лучший способ конвертировать гнездо в treemap - это указать функцию доступа детей с помощью Treemap.children().

В примере масштабируемого treemap для него требуются не только "дети", но также "имя" и "размер". Вы можете сделать это:

1) измените функции доступа этих свойств, чтобы они продолжали использовать "ключ" и "значение".

Измените исходный код .

1.1) строка 79 и 86:

 .style("fill", function(d) { return color(d.parent.name); });

 .text(function(d) { return d.name; })

Заменить ".name" на ".YOUR_NAME_KEY" (т.е. ".key" )

 .style("fill", function(d) { return color(d.parent.YOUR_NAME_KEY); });

 .text(function(d) { return d.YOUR_NAME_KEY; })

1.2) строка 47:

var treemap = d3.layout.treemap()
.round(false)
.size([w, h])
.sticky(true)
.value(function(d) { return d.size; });

Добавить строку, чтобы указать функцию доступа для детей. (i.e ".values" )

var treemap = d3.layout.treemap()
.round(false)
.size([w, h])
.sticky(true)
.value(function(d) { return d.YOUR_SIZE_KEY; })
.children(function(d){return d.YOUR_CHILDREN_KEY});

1.3) строка 97 и 51:

function size(d) {
  return d.size;
}

Замените ".size" на ".YOUR_SIZE_KEY" (вы не упомянули в своем результирующем JSON)

function size(d) {
  return d.YOUR_SIZE_KEY;
}

P.S. Возможно, что-то пропущено, вам нужно убедиться в этом сами.

2) преобразуйте структуру JSON в соответствие с примером Array.map().

Ответ 2

Я полностью согласен с @Anderson, что самый простой подход к этой проблеме - использовать методы children(function) и .value(function) древовидной карты для указания имен свойств во вложенном наборе данных.

Однако недавно был опубликован дублирующий вопрос, в котором спрашивающий специально обращается за помощью, используя подход Array.map. Итак, вот оно:

Метод map(function) массива создает новый массив, где каждый элемент в массиве является результатом выполнения указанной функции для каждого элемента исходного массива. В частности, функция запускается с тремя аргументами: элемент из исходного массива, индекс этого элемента и исходный массив в целом. В целях управления именами свойств нам нужен только первый аргумент.

Вложенные данные в исходном посте имеют три уровня, эквивалентных трем ключевым функциям. Поэтому нам понадобится трехуровневая функция отображения:

var treeData = {
    "key": "World",
    "values": d3.nest()
        .key(function(d) {
            return d.Major_Region;
        })
        .key(function(d) {
            return d.Region;
        })
        .key(function(d) {
            return d.Country;
        })
        .entries(pop)
};

var treeData2 = {
    "name": "World",
    "children": treeData.values.map(function(major) {

        return {
            "name": major.key,
            "children": major.values.map(function(region) {

                return {
                    "name": region.key,
                    "children": region.values.map(function(country) {

                        return {
                            "name": country.key,
                            "children": country.values
                        };

                    }) //end of map(function(country){
                };

            }) //end of map(function(region){
        };

    }) //end of map(function(major){
}; //end of var declaration

Вы также можете реализовать это с помощью рекурсивной функции, что было бы особенно полезно, если бы у вас было гораздо больше уровней вложенности.

Ответ 3

Эй, ребята, я думаю, что нашел довольно простое решение. Я сделал очень красивое вложение большого набора данных (400 000 строк) для иерархической диаграммы диаграммы очень оптимизированным способом. Он использует библиотеку Underscore и дополнительную функцию _.nest. Просто загрузите и включите необходимые две библиотеки

"подчеркивание-min.js" "underscore.nest.js"

Затем используйте функцию _.nest для создания вашей структуры. Здесь моя строка:

var newdata = _.nest(data, ["Material", "StudyName"]);

"Материал" и "StudyName" - это столбцы, в которые я хочу сгруппировать свою структуру.

Существуют и другие варианты использования этой функции, если вам нужно выполнить больше вещей, но я оставлю это как

Ответ 4

Поскольку d3-collection устарела в пользу d3.array, мы можем использовать d3.rollups для достижения того, что раньше работало с d3.nest:

var input = [
  { "Continent": "Europe", "Country": "Spain", "City": "Madrid", "value": "3" },
  { "Continent": "Europe", "Country": "Spain", "City": "Barcelona", "value": "30" },
  { "Continent": "Europe", "Country": "France", "City": "Paris", "value": "243" },
  { "Continent": "America", "Country": "Argentina", "City": "Buenos Aires", "value": "300" },
  { "Continent": "America", "Country": "Argentina", "City": "Buenos Aires", "value": "250" },
  { "Continent": "America", "Country": "Argentina", "City": "Rosario", "value": "200" }
];

// Nesting:
var rolled_up = d3.rollups(
  input,                           // The array on which to apply the rollup
  vs => d3.sum(vs, v => +v.value), // The reducing function to apply on rollups' leafs
  d => d.Continent,                // A first level of nesting
  d => d.Country                   // A second level of nesting
);

// Formatting:
var output = {
  key: "World",
  values: rolled_up.map(x => ({
    key: x[0], // continent
    values: x[1].map(x => ({
      key: x[0], // country
      values: x[1]
    }))
  }))
}

console.log(output);
<script src="https://d3js.org/d3-array.v2.min.js"></script>