'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 |
|---|
