I am using a D3.js to create a line chart using the general update pattern. I have two different types of data. The first type uses an abbreviated month key and the other the day of the month.
The problem I am experiencing is that the line doesn't transitions properly from one data type to the other. I have read some documentation and it stated that when updating d3 updates the lines using the index of each element. But you can change this by defining which variable D3 should watch when updating the chart.
So in order to accomplish this I declared inside the data function that D3 should use the key
variable in the data arrays to check if two data points are the same. But in my snippet example at the bottom you can see that the update doesn't work properly. Instead of loading the full new line from the bottom. It transitions the first line into the second one but they clearly have a different key.
I have updated the code:
The problem wasn't explained correctly. I want to update the line where each point on the line should interpolate to the next point. Which in the snippet in the bottom is working. If it switches from the first to the second array, where all the keys are the same. The line should do as in the snippet and just interpolate.
But if I enter a completely new data with all new keys(like in the third array in the snippet), it should show the line which interpolates from the bottom(just like when entering the line the first time the application is loaded) of the chart and not interpolates from the its previous position. This is because in the project I am using the line also consists of points(circles) and these also transition from the bottom when using a new array.
this.area = this.area
.data([data], d => d.key)
new Vue({
el: "#app",
data() {
return {
index: 0,
data: [
[{
key: "Jan",
value: 5787
},
{
key: "Feb",
value: 6387
},
{
key: "Mrt",
value: 7375
},
{
key: "Apr",
value: 6220
},
{
key: "Mei",
value: 6214
},
{
key: "Jun",
value: 5205
},
{
key: "Jul",
value: 5025
},
{
key: "Aug",
value: 4267
},
{
key: "Sep",
value: 6901
},
{
key: "Okt",
value: 5800
},
{
key: "Nov",
value: 7414
},
{
key: "Dec",
value: 6547
}
],
[{
key: "Jan",
value: 4859
},
{
key: "Feb",
value: 5674
},
{
key: "Mrt",
value: 6474
},
{
key: "Apr",
value: 7464
},
{
key: "Mei",
value: 6454
},
{
key: "Jun",
value: 5205
},
{
key: "Jul",
value: 6644
},
{
key: "Aug",
value: 5343
},
{
key: "Sep",
value: 5363
},
{
key: "Okt",
value: 5800
},
{
key: "Nov",
value: 4545
},
{
key: "Dec",
value: 5454
}
],
[{
"key": 1,
"value": 4431
},
{
"key": 2,
"value": 5027
},
{
"key": 3,
"value": 4586
},
{
"key": 4,
"value": 7342
},
{
"key": 5,
"value": 6724
},
{
"key": 6,
"value": 6070
},
{
"key": 7,
"value": 5137
},
{
"key": 8,
"value": 5871
},
{
"key": 9,
"value": 6997
},
{
"key": 10,
"value": 6481
},
{
"key": 11,
"value": 5194
},
{
"key": 12,
"value": 4428
},
{
"key": 13,
"value": 4790
},
{
"key": 14,
"value": 5825
},
{
"key": 15,
"value": 4709
},
{
"key": 16,
"value": 6867
},
{
"key": 17,
"value": 5555
},
{
"key": 18,
"value": 4451
},
{
"key": 19,
"value": 7137
},
{
"key": 20,
"value": 5353
},
{
"key": 21,
"value": 5048
},
{
"key": 22,
"value": 5169
},
{
"key": 23,
"value": 6650
},
{
"key": 24,
"value": 5918
},
{
"key": 25,
"value": 5679
},
{
"key": 26,
"value": 5546
},
{
"key": 27,
"value": 6899
},
{
"key": 28,
"value": 5541
},
{
"key": 29,
"value": 7193
},
{
"key": 30,
"value": 5006
},
{
"key": 31,
"value": 6580
}
]
]
}
},
mounted() {
// set the dimensions and margins of the graph
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 30
},
width = 500 - margin.left - margin.right;
this.height = 200 - margin.top - margin.bottom;
// append the svg obgect to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
this.svg = d3
.select("#my_dataviz")
.append("svg")
.attr(
"viewBox",
`0 0 ${width + margin.left + margin.right} ${this.height +
margin.top +
margin.bottom}`
)
.attr("preserveAspectRatio", "xMinYMin")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// set the ranges
this.xScale = d3
.scalePoint()
.range([0, width])
.domain(
this.data.map(function(d) {
return d.key;
})
)
.padding(0.5);
this.yScale = d3.scaleLinear().rangeRound([this.height, 0]);
this.yScale.domain([0, 7000]);
// Draw Axis
this.xAxis = d3.axisBottom(this.xScale);
this.xAxisDraw = this.svg
.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${this.height})`);
this.yAxis = d3
.axisLeft(this.yScale)
.tickValues([0, 7000])
.tickFormat(d => {
if (d > 1000) {
d = Math.round(d / 1000);
d = d + "K";
}
return d;
});
this.yAxisDraw = this.svg.append("g").attr("class", "y axis");
this.update(this.data[this.index]);
},
methods: {
swapData() {
if (this.index === 2) this.index = 0;
else this.index++;
this.update(this.data[this.index]);
},
update(data) {
// Update scales.
this.xScale.domain(data.map(d => d.key));
this.yScale.domain([0, 7000]);
// Set up transition.
const dur = 1000;
const t = d3.transition().duration(dur);
// Update line.
this.line = this.svg.selectAll(".line")
this.line = this.line
.data([data], d => d.key)
.join(
enter => {
enter
.append("path")
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "#206BF3")
.attr("stroke-width", 4)
.attr(
"d",
d3
.line()
.x(d => {
return this.xScale(d.key);
})
.y(() => {
return this.yScale(0);
})
)
.transition(t)
.attr(
"d",
d3
.line()
.x(d => {
return this.xScale(d.key);
})
.y(d => {
return this.yScale(d.value);
})
);
},
update => {
update.transition(t).attr(
"d",
d3
.line()
.x(d => {
return this.xScale(d.key);
})
.y(d => {
return this.yScale(d.value);
})
);
},
exit => exit.remove()
);
// Update Axes.
this.yAxis.tickValues([0, 7000]);
if (data.length > 12) {
this.xAxis.tickValues(
data.map((d, i) => {
if (i % 3 === 0) return d.key;
else return 0;
})
);
} else {
this.xAxis.tickValues(
data.map(d => {
return d.key;
})
);
}
this.yAxis.tickValues([0, 7000]);
this.xAxisDraw.transition(t).call(this.xAxis.scale(this.xScale));
this.yAxisDraw.transition(t).call(this.yAxis.scale(this.yScale));
}
}
})
<div id="app">
<button @click="swapData">Swap</button>
<div id="my_dataviz" class="flex justify-center"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://d3js.org/d3.v6.js"></script>