Реструктуризация CSV-файл с d3js


В моей ниже код я реструктуризировали следующие CSV-файл с что-то вроде этого:

date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U

К этому:

{date: "2017-01", E: 3, U: 1}

Используя d3.nest() С rollup метод.

Единственное, что я наметила несколько значений типа вручную такой:

var lineData = nestData.map(function(d) {
  return {date: d.key, E: d.values[0].value, U: d.values[1].value};
}); 

всегда жду видах в порядке. Я делаю это просто сортировка данных по type а затем повторно Сортировать по date снова.

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

Вот весь код:

var csvData = 
`date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;

var durations = 0;

var parseTime = d3.timeParse("%Y-%m");

var margin = {top: 25, right: 25, bottom: 25, left: 25},
    width = 420 - margin.left - margin.right,
    height = 185 - margin.top - margin.bottom;

var g = d3.select("#chart").append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
.append("g")
  .attr("transform", 
    "translate(" + margin.left + "," + margin.top + ")");

var x = d3.scaleTime().range([0, width]),
    y = d3.scaleLinear().range([height, 0]),
    z = d3.scaleOrdinal(d3.schemeCategory10);

var xAxis = d3.axisBottom(x)
    .tickFormat(d3.timeFormat("%B"))
    .ticks(3);

var yAxis = d3.axisLeft(y).ticks(4);

var line = d3.line()
    .curve(d3.curveCardinal)
    .x(function(d) { return x(d.date); })
    .y(function(d) { return y(d.lines); });

g.append("g")
    .attr("class", "axis axis--x")
    .attr("transform", "translate(0," + height + ")");

g.append("g")
    .attr("class", "axis axis--y");

var data = d3.csvParse(csvData, function(d) {
  d.date = d.date;
  d.type = d.type
  return d;
}).sort((a, b) => a.type - b.type)

  var nestData = d3.nest()
    .key(d => d.date)
    .key(d => d.type)
    .rollup(leaves => leaves.length)
    .entries(data);

  console.log("Nested: ", nestData)
  
  var lineData = nestData.map(function(d) {
    return {date: d.key, E: d.values[0].value, U: d.values[1].value};
  });

  lineData.forEach(function(d) {
    d.date = parseTime(d.date);
  })

  lineData.sort((a, b) => a.date - b.date)

  console.log("Mapped: ", lineData)

  parsed(lineData);

  function parsed(dataTest) {

    var keys = ["E","U"]

    var newData = keys.map(function(id) {
      return {
        id: id,
        values: dataTest.map(function(d) {
          return {date: d.date, lines: d[id]};
        })
      };
    });

    console.log("Mapped w/key: ", newData)

    z.domain(newData.map(function(c) { return c.id; }));

    var max = d3.max(dataTest, d => d3.max([d.E, d.U]));

    y.domain([0, max]).nice();

    x.domain(d3.extent(dataTest, d => d.date));

    g.selectAll(".axis.axis--y").transition()
      .duration(durations)
      .call(yAxis);

    g.selectAll(".axis.axis--x").transition()
        .duration(durations)
        .call(xAxis);

    var lineValues = g.selectAll(".lineValues")
      .data(newData);

    lineValues = lineValues
      .enter()
    .append("path")
      .attr("class", "line lineValues")
      .style("stroke", function(d) { return z(d.id); })
      .merge(lineValues);
      
    lineValues.transition()
      .duration(durations)
      .attr("d", function(d) { return line(d.values) })

  }
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
<html>
<head>
<meta charset ="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>

<style type="text/css">
  
.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}

</style>
</head>

<body>

<div id="chart"></div>

<script>
</script>

</body>
</html> 



564
2
задан 7 февраля 2018 в 03:02 Источник Поделиться
Комментарии
1 ответ

Во-первых: удаление строки функция, которая является анонимной функции в качестве второго аргумента csvParse...

var data = d3.csvParse(csvData, function(d) {
d.date = d.date;
d.type = d.type
return d;
})

... потому что ты ничего не меняем!

Так, это может быть просто:

var data = d3.csvParse(csvData);

Возвращаясь к вашему вопросу:

Действительно, вам не нужно ссылаться на массив индексов, который заставляет вас, чтобы отсортировать данные массива, а затем отсортировать полученный массив... это не только сбивает с толку и приводит к ошибкам, но и требовательна к ресурсам компьютера браузер: сортировка больших массивов объектов может занять довольно много времени. Это хорошая идея избежать сортировки, особенно потому, что, как мы увидим, она вам не нужна.

Есть способ, чтобы пропустить этот шаг, сделав его автоматическим. Лучше, вы можете сделать все это автоматически!

На мой предлагаемое решение, вам даже не нужно установить ключи, как и ты сейчас...

var keys = ["E","U"];

Вы можете легко получить все уникальные type значения:

var keys = [...new Set(data.map(function(d) {
return d.type
}))];

А потом, создав свой lineData:

var lineData = nestData.map(function(d) {
var obj = {};
obj.date = d.key;
keys.forEach(function(e) {
obj[e] = d.values.find(function(f) {
return f.key === e
}).value
});
return obj;
});

Приведенный выше код будет работать для любого количества различных типов вы есть, и поскольку у вас уже есть даты в хронологическом порядке, вам не нужен никакой sort.

Это, Короче, это то, что делает функция:


  1. Для каждого map взаимодействия мы создаем новый объект:

    var obj = {};

  2. Мы поставили пару ключ/значение даты, так как всегда есть дата:

    obj.date = d.key;

  3. Затем, для каждого значения в keys массив, мы находим соответствующее значение values массив:

    keys.forEach(function(e) {
    obj[e] = d.values.find(function(f) {
    return f.key === e
    }).value
    });

  4. Наконец, мы возвращаем объект:

    return obj;

Вот демо, используя только соответствующие части кода:



var csvData = `date,type
2017-01,E
2017-01,E
2017-01,E
2017-01,U
2017-01,U
2017-02,E
2017-02,E
2017-02,U
2017-02,U
2017-02,U
2017-03,U
2017-03,U
2017-03,E
2017-03,E
2017-03,E
2017-03,E`;

var parseTime = d3.timeParse("%Y-%m");

var data = d3.csvParse(csvData);

var keys = [...new Set(data.map(function(d) {
return d.type
}))];

var nestData = d3.nest()
.key(d => d.date)
.key(d => d.type)
.rollup(leaves => leaves.length)
.entries(data);

var lineData = nestData.map(function(d) {
var obj = {};
obj.date = d.key;
keys.forEach(function(e) {
obj[e] = d.values.find(function(f) {
return f.key === e
}).value
});
return obj;
});

lineData.forEach(function(d) {
d.date = parseTime(d.date);
})

console.log("Nested: ", nestData)

console.log("Mapped: ", lineData)


<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>


Теперь, используя этот код, вы можете автоматически создать адекватные lineData массив, независимо от количества и порядка type свойства в массив данных.

1
ответ дан 8 февраля 2018 в 01:02 Источник Поделиться