Удалить старые точки из линейного графика в d3

#d3.js #linegraph

#d3.js #линейный график

Вопрос:

Я пытаюсь создать многострочный график и обновлять данные при нажатии кнопки. В каждой строке я хочу выделить точку пересечения с помощью круговой стрелки. Теперь при нажатии кнопки я смог обновить путь линии, но старые выделенные точки пересечения не удаляются из svgContainer (например, нажатие update2 затем update1 не удаляет последний набор кругов, которые не связаны ни с одной линией).

  <input type="button" onclick="update1()" value="Update" />
  <input type="button" onclick="update2()" value="UpdateDimension_T" />
  <div id="outputViz">

  </div>


<script type="text/javascript">    
var data =  [
    [{'index':1,'score':0},{'index':2,'score':5},{'index':3,'score':10},{'index':4,'score':0},{'index':5,'score':6}],
    [{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7}],
    [{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8}],
    [{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9}],
    [{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10}]
  ];

  var data_O =  [
    [{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7},{'index':6,'score':12}],
    [{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8},{'index':6,'score':13}],
    [{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9},{'index':6,'score':14}],
    [{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10},{'index':6,'score':15}],
    [{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':11},{'index':6,'score':16}]
  ];

  var data_T =  [
    [{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':12},{'index':6,'score':20},{'index':7,'score':15}],
    [{'index':1,'score':6},{'index':2,'score':11},{'index':3,'score':16},{'index':4,'score':6},{'index':5,'score':13},{'index':6,'score':21},{'index':7,'score':16}],
    [{'index':1,'score':7},{'index':2,'score':12},{'index':3,'score':17},{'index':4,'score':7},{'index':5,'score':14},{'index':6,'score':22},{'index':7,'score':17}],
    [{'index':1,'score':8},{'index':2,'score':13},{'index':3,'score':18},{'index':4,'score':8},{'index':5,'score':15},{'index':6,'score':23},{'index':7,'score':18}],
    [{'index':1,'score':9},{'index':2,'score':14},{'index':3,'score':19},{'index':4,'score':9},{'index':5,'score':16},{'index':6,'score':24},{'index':7,'score':19}]
  ];

  var colors = [
    'steelblue',
    'green',
    'red',
    'purple',
    'black'
  ];
  var dataset = ["","Or","Se","Tr","De","Cc"];
  var dataset_O = ["","O_1","O_2","O_3","O_4","O_5","O_6"];
  var dataset_T = ["","T_1","T_2","T_3","T_4","T_5","T_6","T_7"];


  var margin = {top: 20, right: 30, bottom: 30, left: 50},
      width = 960 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom,
      padding = 30;

  var x = d3.scale.linear()
                  .domain([0, dataset.length])
                  .range([0, width]);

  var y = d3.scale.linear()
                  .domain([-1, 16])
                  .range([height, 0]);

  var xAxis = d3.svg.axis()
                    .scale(x)
                    .tickFormat(function(d) { return dataset[d]; })
                    .tickSize(-height)
                    .tickPadding(10)  
                    .tickSubdivide(false)  
                    .orient("bottom");  

  var yAxis = d3.svg.axis()
                    .scale(y)
                    .tickPadding(10)
                    .tickSize(-width)
                    .tickSubdivide(false)  
                    .orient("left");


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

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0,"   height   ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    svg.append("g")
      .attr("class", "y axis")
      .append("text")
      .attr("class", "axis-label")
      .attr("transform", "rotate(-90)")
      .attr("y", (-margin.left)   10)
      .attr("x", -height/2)
      .text('Axis Label');  

    svg.append("clipPath")
      .attr("id", "clip")
      .append("rect")
      .attr("width", width)
      .attr("height", height);

    var line = d3.svg.line()
                    .interpolate("linear")  
                    .x(function(d) { return x(d.index); })
                    .y(function(d) { return y(d.score); });   

    svg.selectAll('.line')
        .data(data)
        .enter()
        .append("path")
        .attr("class", "line")
        .attr('stroke', function(d,i){      
          return colors[i%colors.length];
        })
        .attr("d", line);

    var points = svg.selectAll('.dots')
                    .data(data)
                    .enter()
                    .append("g")
                    .attr("class", "dots")

    points.selectAll('.dot')
        .data(function(d, index){     
          var a = [];
          d.forEach(function(point,i){
            a.push({'index': index, 'point': point});
          });   
          return a;
        })
        .enter()
        .append('circle')
        .attr('class','dot')
        .attr("r", 2.5)
        .attr('fill', function(d,i){  
          return colors[d.index%colors.length];
        })  
        .attr("transform", function(d) { 
          return "translate("   x(d.point.index)   ","   y(d.point.score)   ")"; }
        );

    function update1(){
      var x = d3.scale.linear()
                      .domain([0, dataset_O.length])
                      .range([0, width]);

      var y = d3.scale.linear()
                      .domain([-1, 16])
                      .range([height, 0]).nice();

      xAxis = d3.svg.axis()
                    .scale(x)
                    .tickFormat(function(d) { return dataset_O[d]; })
                    .tickSize(-height)
                    .tickPadding(10)  
                    .tickSubdivide(false)  
                    .orient("bottom"); 

      yAxis = d3.svg.axis()
                    .scale(y)
                    .tickPadding(10)
                    .tickSize(-width)
                    .tickSubdivide(false)  
                    .orient("left");

      var line = d3.svg.line()
                      .interpolate("linear")  
                      .x(function(d) { return x(d.index); })
                      .y(function(d) { return y(d.score); }); 

      svg.selectAll('.line')
        .data(data_O)
        .transition(750)
        .attr("d", line)
        .attr("class", "line");



      // change the x axis
      svg.select(".x.axis").call(xAxis);

      // change the y axis
      svg.select(".y.axis").call(yAxis);

          var points = svg.selectAll('.dots').data(data_O); 

          //UPDATE - HANDLE the current count
          points.selectAll('.dot')
                .data(function(d, index){     
                  var a = [];
                  d.forEach(function(point,i){
                    a.push({'index': index, 'point': point});
                  });   
                  return a;
                })
                .attr("transform", function(d) { 
                  return "translate("   x(d.point.index)   ","   y(d.point.score)   ")"; 
                });



          //ENTER - add the newly added count
          points.selectAll('.dot')
                .data(function(d, index){     
                  var a = [];
                  d.forEach(function(point,i){
                    a.push({'index': index, 'point': point});
                  });   
                  return a;
                })
                .enter()
                .append('circle')
                .attr('class','dot')
                .attr("r", 2.5)
                .attr('fill', function(d,i){  
                  return colors[d.index%colors.length];
                })  
                .attr("transform", function(d) { 
                  return "translate("   x(d.point.index)   ","   y(d.point.score)   ")"; 
                });


           d3.selectAll('g.dots').data(data_O).exit().remove();



    }

    function update2(){
      var x = d3.scale.linear()
                      .domain([0, dataset_T.length])
                      .range([0, width]);

      //var yExtents = d3.extent(d3.merge(data_T), function (d) { return d.score; });
      var y = d3.scale.linear()
                      .domain([-1, 29])
                      .range([height, 0]).nice();

      xAxis = d3.svg.axis()
                    .scale(x)
                    .tickFormat(function(d) { return dataset_T[d]; });

      var line = d3.svg.line()
                      .interpolate("linear")
                      .x(function(d) { return x(d.index); })
                      .y(function(d) { return y(d.score); });

      svg.selectAll('.line')
          .data(data_T)
          .transition(750)
          .attr("d", line)
          .attr("class", "line");

      svg.select(".x.axis").call(xAxis);

      svg.select(".y.axis").call(yAxis);

      var points = svg.selectAll('.dots').data(data_T);

      //ENTER - add the newly added count
      points.selectAll('.dot')
            .data(function(d, index){     
              var a = [];
              d.forEach(function(point,i){
                a.push({'index': index, 'point': point});
              });   
              return a;
            })
            .enter()
            .append('circle')
            .attr('class','dot')
            .attr("r", 2.5)
            .attr('fill', function(d,i){  
              return colors[d.index%colors.length];
            })  
            .attr("transform", function(d) { 
              return "translate("   x(d.point.index)   ","   y(d.point.score)   ")"; 
            });


      //UPDATE - HANDLE the current count
      points.selectAll('.dot')
            .data(function(d, index){     
              var a = [];
              d.forEach(function(point,i){
                a.push({'index': index, 'point': point});
              });   
              return a;
            })
            .attr("transform", function(d) { 
              return "translate("   x(d.point.index)   ","   y(d.point.score)   ")"; 
            });
    }
</script>
  

Вот ссылка на скрипку:
https://jsfiddle.net/aakashjain/1dc57aL7/1 /

Ответ №1:

Вам понадобится выбор «выход»:

 points.selectAll('.dot')
    .data(function(d, index){     
        var a = [];
        d.forEach(function(point,i){
            a.push({'index': index, 'point': point});
        });   
            return a;
        })
    .exit()
    .remove();
  

Вот скрипка обновления :. https://jsfiddle.net/1dc57aL7/2 /

(Просто совет: у вас здесь много дублированного кода. Ваши функции «update1» и «update2» могут быть намного меньше)

Комментарии:

1. Огромное спасибо, Херардо, это решило мою проблему. Хотя я использовал выделение exit() как d3.selectAll(‘g.dots’).data(data_O).exit().remove();, но это не отражало ожидаемых изменений.

2. и спасибо за предупреждение о дублировании кода, я новичок в d3, постараюсь уменьшить длину функции здесь. Если это возможно, не могли бы вы сказать мне, какие части можно удалить?

3. О, здесь много дублированных частей! К сожалению, я нахожусь на своем мобильном телефоне, очень неудобно печатать на JSfiddle, но я уверен, что кто-то еще поможет вам в этом, я предлагаю вам опубликовать его как новый вопрос, если хотите.