【问题标题】:in D3.js how to add/remove datapoints at the same time?在 D3.js 中如何同时添加/删除数据点?
【发布时间】:2018-03-25 16:22:32
【问题描述】:

在下面的示例中,如果我的新数据集有新条目并且删除了一些记录(添加了墨西哥卷饼,删除了苹果),我如何同时反映这些更改?到目前为止,代码推入了一个新栏,但没有删除第一个栏,即使我尝试重新设置 x 轴域,轴也没有更新。

块引用

<!DOCTYPE html>
<html lang="en">
    <head>
      <script src="https://d3js.org/d3.v4.min.js"></script>
        <meta charset="utf-8">
        <title>D3: Loading data from a CSV file</title>
  </head>
    <body>
    <p>Click on this text to update the chart with new data values (once).</p>
        <script type="text/javascript">

      var margin = {top: 20, right: 20, bottom: 30, left: 40},
            w = 600 - margin.left - margin.right,
            h = 300 - margin.top - margin.bottom;
      var padding = 40;

      var data = [
        { "Food": "Apples", "Deliciousness": 9, "new":4 },
        { "Food": "Green Beans", "Deliciousness": 5, "new":4 },
        { "Food": "Egg Salad Sandwich", "Deliciousness": 4, "new":4 },
        { "Food": "Cookies", "Deliciousness": 10, "new":4 },
        { "Food": "Liver", "Deliciousness": 2, "new":4 },
      ];

      data.forEach(function(d) {
        d.Deliciousness = +d.Deliciousness;
      });
            //define key
      var key = function(d) {
        return d.Food;
      }

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

      //initial state
      //scale and axis
      var xScale = d3.scaleBand()
        .domain(d=>d.Food)
        .range([0,w])
        .paddingInner(0.2);
     xScale.domain(data.map(function(d) { return d.Food; }));

      var yScale = d3.scaleLinear()
        .domain([0, d3.max(data, d=>d.Deliciousness)])
        .rangeRound([h,0]);


      var xAxis = d3.axisBottom()
        .scale(xScale)
        .ticks(5);

      var yAxis = d3.axisLeft()
        .scale(yScale)
        .ticks(5);

      //draw rect
      svg.selectAll('rect')
        .data(data, key)
        .enter()
        .append('rect')
        .attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
        .attr('y',d=>yScale(d.Deliciousness))
        .attr('width', xScale.bandwidth())
        .attr('height',d =>h-yScale(d.Deliciousness))
        .attr('fill',function(d){
          if (d===30) return "red";
          return "rgb(0,0,"+d.Deliciousness*10+")" ;});

      //text label
      svg.selectAll("text")
        .data(data)
        .enter()
        .append("text")
        .text(d=>d.Deliciousness)
        .attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length) + 0.4*w/ data.length)
        .attr("y", d=>yScale(d.Deliciousness)+15)
        .attr("fill","white")
        .attr("text-anchor", "middle");

      //draw axis
      svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + padding + ",0)")
        .call(yAxis);

      svg.append("g")
        .attr("class", "axis")
        .attr("transform", "translate(" + margin.left + "," + h + ")")
        .call(xAxis);

      //transition
      d3.select("p")
                .on("click", function() {

                    //New values for dataset
      data = [
        { "Food": "Green Beans", "Deliciousness": 5, "new":4 },
        { "Food": "Egg Salad Sandwich", "Deliciousness": 4, "new":4 },
        { "Food": "Cookies", "Deliciousness": 10, "new":4 },
        { "Food": "Liver", "Deliciousness": 2, "new":4 },
        { "Food": "Burrito", "Deliciousness": 7, "new":4 }];

          xScale.domain(data.map(function(d) { return d.Food; }));

        //Update all rects
          var bars = svg.selectAll("rect")
                       .data(data, key);

          bars.enter()
            .append("rect")
                            // <-- This makes it a smooth transition!
            .attr("x", w)

            .attr('y',d=>yScale(d.Deliciousness))
            .attr("width", xScale.bandwidth())
            .attr('height',d =>h-yScale(d.Deliciousness))
            .merge(bars)                            //Merges the enter selection with the update selection
                        .transition()                           //Initiate a transition on all elements in the update selection (all rects)
                        .duration(500)
            .attr('x',(d,i) => margin.left + i * ((w + 20 ) / data.length))
                .attr('y',d=>yScale(d.Deliciousness))
                .attr('width', xScale.bandwidth())
                .attr('height',d =>h-yScale(d.Deliciousness))
                });





        </script>
    </body>
</html>

并且附加了当前错误的输出。 谢谢!

【问题讨论】:

    标签: d3.js data-binding transition


    【解决方案1】:

    你错过了两件事。一,.remove 退出选择,二,更新你的 x 轴。

    xScale.domain(data.map(function(d) {
      return d.Food;
    }));
    
    // redraw x-axis
    svg.select('.xaxis')
      .call(xAxis);
    
    //Update all rects
    var bars = svg.selectAll("rect")
      .data(data, key);
    
    // remove those things exitiing
    bars.exit().remove();
    

    运行代码:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <script src="https://d3js.org/d3.v4.min.js"></script>
      <meta charset="utf-8">
      <title>D3: Loading data from a CSV file</title>
    </head>
    
    <body>
      <p>Click on this text to update the chart with new data values (once).</p>
      <script type="text/javascript">
        var margin = {
            top: 20,
            right: 20,
            bottom: 30,
            left: 40
          },
          w = 600 - margin.left - margin.right,
          h = 300 - margin.top - margin.bottom;
        var padding = 40;
    
        var data = [{
          "Food": "Apples",
          "Deliciousness": 9,
          "new": 4
        }, {
          "Food": "Green Beans",
          "Deliciousness": 5,
          "new": 4
        }, {
          "Food": "Egg Salad Sandwich",
          "Deliciousness": 4,
          "new": 4
        }, {
          "Food": "Cookies",
          "Deliciousness": 10,
          "new": 4
        }, {
          "Food": "Liver",
          "Deliciousness": 2,
          "new": 4
        }, ];
    
        data.forEach(function(d) {
          d.Deliciousness = +d.Deliciousness;
        });
        //define key
        var key = function(d) {
          return d.Food;
        }
    
        var svg = d3.select("body")
          .append("svg")
          .attr("width", w + margin.left + margin.right + padding)
          .attr("height", h + margin.top + margin.bottom)
          .append("g")
          .attr("transform", "translate(" + margin.left + "," +
            margin.top + ")");
    
        //initial state
        //scale and axis
        var xScale = d3.scaleBand()
          .domain(d => d.Food)
          .range([0, w])
          .paddingInner(0.2);
    
        xScale.domain(data.map(function(d) {
          return d.Food;
        }));
    
        var yScale = d3.scaleLinear()
          .domain([0, d3.max(data, d => d.Deliciousness)])
          .rangeRound([h, 0]);
    
    
        var xAxis = d3.axisBottom()
          .scale(xScale)
          .ticks(5);
    
        var yAxis = d3.axisLeft()
          .scale(yScale)
          .ticks(5);
    
        //draw rect
        svg.selectAll('rect')
          .data(data, key)
          .enter()
          .append('rect')
          .attr('x', (d, i) => margin.left + i * ((w + 20) / data.length))
          .attr('y', d => yScale(d.Deliciousness))
          .attr('width', xScale.bandwidth())
          .attr('height', d => h - yScale(d.Deliciousness))
          .attr('fill', function(d) {
            if (d === 30) return "red";
            return "rgb(0,0," + d.Deliciousness * 10 + ")";
          });
    
        //text label
        svg.selectAll("text")
          .data(data)
          .enter()
          .append("text")
          .text(d => d.Deliciousness)
          .attr('x', (d, i) => margin.left + i * ((w + 20) / data.length) + 0.4 * w / data.length)
          .attr("y", d => yScale(d.Deliciousness) + 15)
          .attr("fill", "white")
          .attr("text-anchor", "middle");
    
        //draw axis
        svg.append("g")
          .attr("class", "axis")
          .attr("transform", "translate(" + padding + ",0)")
          .call(yAxis);
    
        svg.append("g")
          .attr("class", "xaxis")
          .attr("transform", "translate(" + margin.left + "," + h + ")")
          .call(xAxis);
    
        //transition
        d3.select("p")
          .on("click", function() {
    
            //New values for dataset
            data = [{
              "Food": "Green Beans",
              "Deliciousness": 5,
              "new": 4
            }, {
              "Food": "Egg Salad Sandwich",
              "Deliciousness": 4,
              "new": 4
            }, {
              "Food": "Cookies",
              "Deliciousness": 10,
              "new": 4
            }, {
              "Food": "Liver",
              "Deliciousness": 2,
              "new": 4
            }, {
              "Food": "Burrito",
              "Deliciousness": 7,
              "new": 4
            }];
    
            xScale.domain(data.map(function(d) {
              return d.Food;
            }));
            
            svg.select('.xaxis')
              .call(xAxis);
    
            //Update all rects
            var bars = svg.selectAll("rect")
              .data(data, key);
    
            bars.exit().remove();
    
            bars.enter()
              .append("rect")
              // <-- This makes it a smooth transition!
              .attr("x", w)
    
            .attr('y', d => yScale(d.Deliciousness))
              .attr("width", xScale.bandwidth())
              .attr('height', d => h - yScale(d.Deliciousness))
              .merge(bars) //Merges the enter selection with the update selection
              .transition() //Initiate a transition on all elements in the update selection (all rects)
              .duration(500)
              .attr('x', (d, i) => margin.left + i * ((w + 20) / data.length))
              .attr('y', d => yScale(d.Deliciousness))
              .attr('width', xScale.bandwidth())
              .attr('height', d => h - yScale(d.Deliciousness));
    
    
          });
      </script>
    </body>
    
    </html>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-29
      • 2014-01-30
      • 2013-07-13
      • 2021-05-26
      • 2016-11-14
      • 2021-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多