'How to update d3 multiline chart with data change?

I am working on Multiline graph d3 graph version 7. My data is like

 data: GraphData[] = [
    {
      category: 'a',
      date: '2022-01-01',
      numberIssue: 10
    },
    {
      category: 'a',
      date: '2022-01-02',
      numberIssue: 20
    },
{
      category: 'b',
      date: '2022-01-01',
      numberIssue: 25
    },
    {
      category: 'b',
      date: '2022-01-02',
      numberIssue: 89
    }
  ];

I initialize my svg like this

margin = { top: 50, right: 50, bottom: 150, left: 50 };
  width = 700 - this.margin.left - this.margin.right;
  height = 500 - this.margin.top - this.margin.bottom;
  private colors = ['red', 'blue', 'yellow', 'green', 'brown'];

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

And under ngOnInit method, I added code for scaling and draw the axis and lines

 const x = d3.scalePoint()
      .rangeRound([0, this.width]);

    // Add Y axis
    const y = d3.scaleLinear()
      .range([this.height, 0]);
    const xScale = d3
      .scalePoint()
      .domain(this.data.map((d: any) => { return d.date }))
      .range([0, this.width])
    // y-scale
    const yScale = d3
      .scaleLinear()
      .domain([0, d3.max(this.data.map((d: any) => d.numberIssue))])
      .range([this.height, 0]);
    // Group the entries by symbol
    const dataNest = Array.from(
      d3.group(this.data, d => d.category), ([key, value]) => ({ key, value })
    );

    var legendSpace = (this.width - 100) / dataNest.length; // spacing for the legend

    const line = d3
      .line()
      .defined(true)
      .x((d: any) => xScale(d.date) || 0)
      .y((d: any) => yScale(d.numberIssue));


    this.svg.selectAll('.xAxis').remove();
    this.svg.selectAll('.yAxis').remove();
    this.svg.selectAll('.line').remove();
    this.svg.selectAll('.legend').remove();
    this.svg.selectAll('.grid').remove();

    x.domain(this.data.map((d: any) => { return d.date }));
    y.domain([0, d3.max(this.data, ((d: any) => {
      return d.numberIssue;
    }))])
    this.svg.append("g")
      .attr('class', 'xAxis')
      .attr("transform", `translate(0, ${this.height})`)
      .call(d3.axisBottom(x).tickValues(this.data.map((d: any) => { return d.date })))
      .selectAll('text')
      .style('text-anchor', 'end')
      .style("font-size", 10)
      .attr('dx', '-.8em')
      .attr('dy', '.15em')
      .attr('transform', 'rotate(-65)');

    this.svg.append("g")
      .attr('class', 'yAxis')
      .call(
        d3.axisLeft(y).ticks(4).tickFormat(d3.format('d'))
      );
    dataNest.forEach((d1: any, i: any) => {

      // Data line

      this.svg.append("path")
        .datum([dataNest])
        .join("path")
        .attr("fill", "none")
        .attr("class", "line")
        .style("stroke", this.colors[i])
        .attr("d", line(d1.value));

      // Add the Legend
      this.svg.append("text")
        .attr("x", (legendSpace / 2) + i * legendSpace)  // space legend
        .attr("y", this.height + (this.margin.bottom / 2) + 15)
        .attr("class", "legend")    // style the legend
        .style("fill", this.colors[i])
        .text(DeSlugifyPipe.prototype.transform(d1.key));
    });

But when this component is rerendered, it will draw the multiline chart 2nd time, It is not updating the previous one. So can someone can help with this?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source