D3 exit()无法在分组条形图中发挥预期的作用

时间:2018-11-20 15:31:16

标签: javascript d3.js

我无法理解分组条形图中的exit()选择如何工作。我的示例中只有空白的exit()选择,因此在更新图表时不会从图表中删除任何内容。

这类似于此处发布的问题:d3 grouped bar chart update pattern not working。但是由于我在'g'对象后附加了chartArea,所以我认为该解决方案不适用。

我从这里松散地遵循分组/堆叠的条形图示例:https://bl.ocks.org/aholachek/fb0c1cd7ea9707bc8ff55a82402c54b1

完整的jsfiddle https://jsfiddle.net/fg_ti/ka306sjc/68/和代码:

var data1 = [
  {
    "sex": "female",
    "n_patients": 5,
    "grouping":"A"
  },
  {
    "sex": "male",
    "n_patients": 10,
    "grouping": "A"
  },
  {
    "sex": "female",
    "n_patients": 25,
    "grouping":"B"
  },
  {
    "sex": "male",
    "n_patients": 10,
    "grouping":"B"
  }];
var data2 = [
  {
    "sex": "female",
    "n_patients": 62,
    "grouping":"A"
  },
  {
    "sex": "male",
    "n_patients": 55,
    "grouping":"A"
  },
  {
    "sex": "female",
    "n_patients": 25,
    "grouping": "B"
  },
  {
    "sex": "male",
    "n_patients": 83,
    "grouping":"B"
  },
  {
   "sex": "female",
   "n_patients": 25,
   "grouping": "D"},
  {
    "sex": "male",
    "n_patients": 83,
    "grouping": "D"
   }];

width = 350;
height = 450;

var initData = d3.nest().key(d => d.grouping).entries(data1)
var margin = ({top:10, right:10, bottom:10, left:30});
var Gwidth = width - margin.left - margin.right
var Gheight = height - margin.top - margin.bottom
var barPadding = 0.1;

var colors = ['#ffe1e1', '#d1ecfd']
svg = d3.select('body').append('svg')
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
var topG = svg.append('g')
    .attr('transform', 'translate(' + margin.left + ',' + margin.top +')')


// Initial scale

// Scale between the keys (i.e. b/w age groups, edu, etc`)
var scaleX = d3.scaleBand()
  .domain(initData.map(d => d.key))
  .range([0, Gwidth])
  .padding(barPadding);

var scaleColors = d3.scaleOrdinal()
    .range(colors)

// Initial axis
var yAxis = topG.append('g')
  .attr("class", "y axis")

var xAxis = topG.append('g')
    .attr("class", "x axis")

xAxis.call(d3.axisBottom(scaleX))
    .attr("transform", 'translate(' + 0 + "," + Gheight + ')');

var chartArea = topG.append("g")
    .attr("class", "chartArea");



// UPDATE FUNCTION - will be called by r2d3.onRender()
function update(inData) {

  // Reshape data
  var newData = d3.nest()
    .key(d => d.grouping)
    .entries(inData);


  var maxY = d3.max(newData, d => d3.max(d.values, k => k.n_patients));
  grouping1Names = newData.map(d => d.key);
  grouping2Names = newData[0].values.map(d => d.sex);
  var t = 1000;

  // Scales used in updates 
  var scaleY = d3.scaleLinear()
    .domain([0, maxY])
    .range([Gheight, 0]);

  var scaleX = d3.scaleBand()
    .domain(grouping1Names)
    .range([0, Gwidth])
    .padding(barPadding);

  var scaleX1 = d3.scaleBand()
    .domain(grouping2Names)
    .rangeRound([0, scaleX.bandwidth()]);


  // Perform the data join

   var barGroupWithData = chartArea
      .selectAll('.barGroup')
      .data(newData);

    barGroupWithData.exit().remove();

   // Join rect elements with data - specified with keys
   var bars = barGroupWithData.enter()
      .append("g")
      .attr("transform", d => "translate(" + scaleX(d.key) + ",0)")
      .attr("fill", "steelblue")
      .merge(barGroupWithData)
      .selectAll("rect")
          .data(d => Object.keys(d.values)
                          .map(k => ({ keyL2: grouping2Names[k], value: d.values[k].n_patients }) ));



  console.log(bars)

  // Remove rect elements joined with data that is no longer present
  bars.exit().remove()

  bars.enter()
    .append("rect")
    .attr("fill", d => scaleColors(d.keyL2))
    .attr("y", d => scaleY(0))
    .merge(bars)
    .attr("x", (d) => scaleX1(d.keyL2))
    .attr("width", scaleX1.bandwidth())
    .transition()
    .duration(t)
    .ease(d3.easeLinear)
    .attr('y', d => scaleY(d.value))
    .attr("height", d => scaleY(0) - scaleY(d.value));

  console.log(bars)

  // Udpate axes
  yAxis.transition()
    .duration(t)
    .call(d3.axisLeft(scaleY))

  xAxis.transition()
    .duration(t)
    .call(d3.axisBottom(scaleX))

}

//


update(data1);

 // Update the data
  setInterval(function (newDat) {

            if(Math.random()>0.5) {
            d = data1
            } else {
            d = data2
            }


            return update(d);
        }, 3000);

我怀疑我没有正确加入数据,但是无法查明错误的出处。该问题的第一个发布答案似乎很接近,但不适用于我的解决方案:Exit() is not working for d3 group bar chart

是否有建议从图表中正确删除旧数据?

====================编辑============

为澄清起见,我修改了数据以更好地突出问题(updated jsfidlde)。数据似乎可以很好地加入rect元素-每次更新时,都会添加新的小节。但是,不会删除旧的rect元素。 由于将数据连接到rect的键是这样指定的:

(.data(d => Object.keys(d.values)
                              .map(k => ({ keyL2: grouping2Names[k], value: d.values[k].n_patients }) ));` `.enter()`

因此,我希望.data()将传入数据与现有rect元素中的数据进行匹配。 如果传入数据的n_patientsgrouping具有不同的值,我认为d3会将新数据识别为“正在输入”,并附加地添加n_patient中已经存在的数据或grouping的值与“退出”并删除的新数据不匹配。这是基于以下问题的答案:D3 Key Function;以及来自Mike Bostock的old blog post

由于在每个rect调用中都添加了新的.enter(),因此d3似乎正在识别“输入”数据,但未按照编写代码的方式识别“正在退出”数据。有人可以阐明这一点吗?

0 个答案:

没有答案