d3第一次运行时不会附加圆圈

问题描述

我正在使用嵌套数据集和以下代码在d3 v5中绘制圆形:

const scatterGroup = svg.selectAll(".scatterGroup").data(data);

scatterGroup.exit().remove();

scatterGroup
  .enter()
  .append("g")
  .attr("class","scatterGroup")
  .attr("fill",(d,i) => color[i])
  .attr("stroke",i) => color[i])
  .append("g")
  .attr("class","scatterPoints");

const scatterPoints = scatterGroup
  .selectAll(".scatterPoints")
  .data((d) => d);

scatterPoints
  .enter()
  .append("circle")
  .attr("class","scatterPoints")
  .attr("cx",i) => xScale(d.x))
  .attr("cy",i) => yScale(d.y))
  .attr("r",5);

scatterPoints.exit().remove();

const scatterUpdate = scatterGroup
  .transition()
  .duration(500)
  .attr("fill",i) => color[i]);

scatterPoints
  .transition()
  .duration(500)
  .attr("cx",i) => yScale(d.y));

在提供数据的第一次运行中没有任何反应。控件在第一次加载时未达到附加圆。当第二次加载数据时,d3将附加圆圈。谁能让我知道首次提供数据时如何使它们出现以及为什么会发生这种情况?

解决方法

之所以会这样,是因为数据是嵌套的,因此在创建scatterPoints之前,您需要.merge() scatterGroup或重新选择它。否则,scatterGroup仍为空,而scatterGroup.enter()保留所有点。

我还从您的代码中删除了.append(g).attr('class','scatterPoints'),因为它使用的是g而不是circle,并且不需要在那里

const svg = d3.select('svg');
const color = ['red','blue'];
const data = [
  [{
    x: 10,y: 10
  },{
    x: 40,y: 100
  }],[{
    x: 25,y: 50
  }]
];
const newData = [
  [{
    x: 10,y: 20
  },{
    x: 50,y: 40
  }]
];

function draw(data) {
  const scatterGroup = svg.selectAll(".scatterGroup").data(data);

  scatterGroup.exit().remove();

  const scatterGroupNew = scatterGroup
    .enter()
    .append("g")
    .attr("class","scatterGroup")
    .attr("fill",(d,i) => color[i])
    .attr("stroke",i) => color[i]);

  // Equivalent:
  //const scatterPoints = svg.selectAll(".scatterGroup")
  //  .selectAll(".scatterPoint")
  //  .data((d) => d);

  const scatterPoints = scatterGroup
    .merge(scatterGroupNew)
    .selectAll(".scatterPoint")
    .data((d) => d);

  scatterPoints.exit().remove();

  const scatterPointsNew = scatterPoints
    .enter()
    .append("circle")
    .attr("class","scatterPoint")
    .attr("r",5);

  scatterPoints.merge(scatterPointsNew)
    .attr("cx",i) => d.x)
    .attr("cy",i) => d.y);
}

draw(data);
setTimeout(() => draw(newData),1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg>
</svg>