正确操作JSON数据以创建D3区域图

Proper manipulation of JSON data to create D3 area chart?

本文关键字:创建 D3 区域 数据 操作 JSON      更新时间:2023-09-26

我在D3中最困难的地方是在将其插入现有模型之前进行正确的数据处理。我试图找出创建一个基于时间的x轴的基本D3区域图所需的最少数据操作量。我从一个JSON对象数组开始,该数组具有date键和Date对象属性,以及其他几个用于填充图表的键值对。

例如:

[{date: Wed Jul 20 2016 00:00:00 GMT-1000 (HST), a: 5, b: 1, c: 9, nothankyou: 90},
{date: Wed Jul 21 2016 00:00:00 GMT-1000 (HST), a: 7, b: 2, c: 10, nothankyou: 70},
{date: Wed Jul 22 2016 00:00:00 GMT-1000 (HST), a: 6, b: 5, c: 3, nothankyou: 50},
...etc...]

目标是创建一个面积图,其中abc的值沿y轴,时间(date)的值沿x轴。需要过滤掉不需要的数据点,例如nothankyou

我以前在另一个项目中使用过d3.nest来类似地处理数据,但在数据已经按日期组织的情况下,这不是过分了吗?

D3区域图本身相当简单(它假设数据已经是D3.nest()-ed):

var format = d3.time.format("%Y-%m-%d");
var margin = {top: 20, right: 30, bottom: 30, left: 40},
    width = 450 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom,
    delay = 500,
    duration = 750;
var x = d3.time.scale()
    .range([0, width]);
var y = d3.scale.linear()
    .range([height, 0]);
var z = d3.scale.category20c();
var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .ticks(d3.time.months);
var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");
var stack = d3.layout.stack()
    .offset("zero")
    .values(function(d) { return d.values; })
    .x(function(d) { return d.date; })
    .y(function(d) { return d.value; });
var nest = d3.nest()
    .key(function(d) { return d.key; });
var area = d3.svg.area()
    .interpolate("cardinal")
    .x(function(d) { return x(d.date); })
    .y0(function(d) { return y(d.y0); })
    .y1(function(d) { return y(d.y0 + d.y); });
var svg = d3.select(".areaChart")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
  totalCrimeData.forEach(function(d) {
    d.date = format.parse(d.date);
    d.value = +d.value;
  });
  var layers = stack(nest.entries(data));
  console.log("layers",layers);
  x.domain(d3.extent(data, function(d) { return d.date; }));
  y.domain([0, d3.max(data, function(d) { return d.y0 + d.y; })]);
  svg.selectAll(".layer")
      .data(layers)
    .enter().append("path")
      .attr("class", "layer")
      .attr("d", function(d) { return area(d.values); })
      .style("fill", function(d, i) { return z(i); });
  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

这是我提出的一个临时解决方案(非D3),用于按照D3设置所需的方式构建数据。欢迎评论。

var data = [ {}, {}, {}, ... ] // see above
var dataSets = ["a","b","c"]
var newArr = [];
data.map(function(a) {
  var prop;
  var _this = this;
  dataSets.map(function(k) {
    prop = a.date+"|"+k;
    if (!_this[prop]) {
      _this[prop] = {
        key: k,
        value: 0,
        date: a.date
      };
        newArr.push(_this[prop]);
      }
      if (prop === a.date+"|"+k) {
        _this[prop].value += parseInt(a[k]);
      }
    });
  }, Object.create(null));
console.log("reduced data", newArr);