d3 v4分组条形图- .data(fn).enter()为空



我使用这个mbostock示例作为指南,但它是在d3 v3中。我已经读到,在v4,选择已经改变,但这似乎不是我的问题,因为数据永远不会改变-这是一个静态图表(目前)。

我有一个对象数组,我希望为每个对象创建一个组(g),并为该对象的每个field1field2创建两个矩形(rect),这些矩形与日期相关。我能够创建组,但是当我.data(d => d),而试图使矩形,输入组似乎是空的。

有人能解释一下这是为什么吗?

jsfield (not working)

UPDATE: jsfiddle (working) –感谢@gerardo-furtado

var models = [
  {
    "date":"2016-10-13T07:00:00.000Z",
    "field1":19,
    "field2":83
  },
  {
    "date":"2016-10-14T07:00:00.000Z",
    "field1":67,
    "field2":93
  },
  {
    "date":"2016-10-15T07:00:00.000Z",
    "field1":10,
    "field2":56
  },
  {
    "date":"2016-10-16T07:00:00.000Z",
    "field1":98,
    "field2":43
  }
];
models = models.map(i => {
  i.date = new Date(i.date);
    return i;
});
var container = d3.select('body'),
    width = 500,
    height = 300,
    margin = {top: 30, right: 20, bottom: 30, left: 50},
    barPadding = .2,
    axisTicks = {qty: 5, outerSize: 0, dateFormat: '%m-%d'};
var svg = container
   .append("svg")
   .attr("width", width)
   .attr("height", height)
   .append("g")
   .attr("transform", `translate(${margin.left},${margin.top})`);
var xScale0 = d3.scaleBand().range([0, width - margin.left - margin.right]).padding(barPadding);
var xScale1 = d3.scaleBand();
var yScale = d3.scaleLinear().range([height - margin.top - margin.bottom, 0]);
var xAxis = d3.axisBottom(xScale0).tickFormat(d3.timeFormat(axisTicks.dateFormat)).tickSizeOuter(axisTicks.outerSize);
var yAxis = d3.axisLeft(yScale).ticks(axisTicks.qty).tickSizeOuter(axisTicks.outerSize);
xScale0.domain(models.map(d => d.date));
xScale1.domain(['field1', 'field2']).range([0, xScale0.bandwidth()]);
yScale.domain([0, d3.max(models, d => d.field1 > d.field2 ? d.field1 : d.field2)]);
var date = svg.selectAll(".date")
  .data(models)
  .enter().append("g")
  .attr("class", "date")
  .attr("transform", d => `translate(${xScale0(d.date)},0)`);
/* Add field1 bars */
var rect = date.selectAll(".bar")
  .data(d => d) // FIXME: the .enter() group seems to contain nothing
  .enter()
  .append("rect")
  .attr("class", "bar")
  .attr("x", d => { xScale1('field1') })
  .attr("y", d => { yScale(d.field1) })
  .attr("width", xScale1.bandwidth())
  .attr("height", d => {
    return height - margin.top - margin.bottom - yScale(d.field1)
  });
/* Add field2 bars */
// var rect = date.selectAll(".bar")
//  .data(d => d)
//  .enter()
//  .append("rect")
//  .attr("class", "bar")
//  .attr("x", d => { xScale1('field2') })
//  .attr("y", d => { yScale(d.field2) })
//  .attr("width", xScale1.bandwidth())
//  .attr("height", d => {
//    return height - margin.top - margin.bottom - yScale(d.field1)
//  });
// Add the X Axis
svg.append("g")
   .attr("class", "x axis")
   .attr("transform", `translate(0,${height - margin.top - margin.bottom})`)
   .call(xAxis);
// Add the Y Axis
svg.append("g")
   .attr("class", "y axis")
   .call(yAxis);

在D3中,data必须是数组。如果你看一下Bostock的例子,layers是一个数组的数组。这是console.log(layers):

的结果
Array[4]
    0:Array[58]
    1:Array[58]
    2:Array[58]
    3:Array[58]
因此,由于layers是数组的数组,当Bostock在后面的代码中这样写时:
.data(function(d) { return d; })

他正在传递一个数组给data,这是有效的。

然而,在您的代码中,您在rect的输入选择中将一个对象传递给data:

对象{日期:星期四Oct 13 2016 18:00:00 GMT+1100, field1: 19, field2: 83}

解决方案:传递一个数组给data。这是我做的唯一更改:

.data(d => [d])
现在你有了一个数组:

[{date: thococ13 2016 18:00:00 GMT+1100, field1: 19, field2: 83}]

这是你更新的小提琴:https://jsfiddle.net/96d3wtys/

PS:你必须调整yheight

最新更新