Reputation: 1160
The following code has multiple paths on a single d3.js plot. I have the initial plot working, displaying the data set d0
. It looks like this on load:
I would like to display the data in d1
when the button is pressed, so it should look like this:
What currently happens is...nothing. No errors in the console, no change to the display, and no change to the DOM (that I can see?).
I've been through a dozen code examples and tutorials and just don't see what's going wrong here. Any help would be greatly appreciated (particularly if with an explanation of what I'm conceptually missing). Thanks!
var d0 = [{
id: "A",
values: [{
x: .25,
y: .9
}, {
x: .75,
y: 1
}]
},
{
id: "B",
values: [{
x: .25,
y: .5
}, {
x: .8,
y: .4
}]
},
{
id: "C",
values: [{
x: .1,
y: .1
}, {
x: .9,
y: .1
}]
}
]
var d1 = [{
id: "A",
values: [{
x: 0,
y: 1
}, {
x: 1,
y: 1
}]
},
{
id: "B",
values: [{
x: 0,
y: .5
}, {
x: 1,
y: .5
}]
},
{
id: "C",
values: [{
x: 0,
y: 0
}, {
x: 1,
y: 0
}]
}
]
var svg = d3.select("svg")
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
}
var width = svg.attr("width") - margin.left - margin.right
var height = svg.attr("height") - margin.top - margin.bottom
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var scaleX = d3.scaleLinear().range([0, width]).domain([0, 1])
var scaleY = d3.scaleLinear().range([height, 0]).domain([0, 1])
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(scaleX));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(scaleY))
var line = d3.line()
.x(function(d) {
return scaleX(d.x)
})
.y(function(d) {
return scaleY(d.y)
});
var lineg = g.selectAll(".lineg")
.data(d0)
.enter()
.append("g")
.attr("class", "lineg");
lineg.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values)
})
function update() {
var i = g.selectAll(".lineg")
.data(d1)
i.enter()
.append("g")
.attr("class", "lineg")
i.exit()
.remove()
g.selectAll(".line")
.attr("d", function(d) {
return line(d.values)
})
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
<br/>
<button onclick="update()">Change</button>
Upvotes: 1
Views: 422
Reputation: 13139
Every SVG element that you call .data
or .datum
on has an internal reference to a data object. In your update call, you updated the data of the g
elements that held the lines, but never of the lines themselves.
I was able to do that with the following code:
i.select(".line")
.datum(function(d) {
return d;
})
.attr("d", function(d) {
return line(d.values)
})
Here, starting from the newly selected groups i
, which you already gave the correct data, I select the line, and then pass it the datum object from the g
directly, through the function. That way, the datum object gets updated, and calling line(d.values)
now actually uses entries from d1
instead of d0
.
var d0 = [{
id: "A",
values: [{
x: .25,
y: .9
}, {
x: .75,
y: 1
}]
},
{
id: "B",
values: [{
x: .25,
y: .5
}, {
x: .8,
y: .4
}]
},
{
id: "C",
values: [{
x: .1,
y: .1
}, {
x: .9,
y: .1
}]
}
]
var d1 = [{
id: "A",
values: [{
x: 0,
y: 1
}, {
x: 1,
y: 1
}]
},
{
id: "B",
values: [{
x: 0,
y: .5
}, {
x: 1,
y: .5
}]
},
{
id: "C",
values: [{
x: 0,
y: 0
}, {
x: 1,
y: 0
}]
}
]
var svg = d3.select("svg")
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
}
var width = svg.attr("width") - margin.left - margin.right
var height = svg.attr("height") - margin.top - margin.bottom
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")
var scaleX = d3.scaleLinear().range([0, width]).domain([0, 1])
var scaleY = d3.scaleLinear().range([height, 0]).domain([0, 1])
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(scaleX));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(scaleY))
var line = d3.line()
.x(function(d) {
return scaleX(d.x)
})
.y(function(d) {
return scaleY(d.y)
});
var lineg = g.selectAll(".lineg")
.data(d0)
.enter()
.append("g")
.attr("class", "lineg");
lineg.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values)
})
function update() {
var i = g.selectAll(".lineg")
.data(d1)
i.enter()
.append("g")
.attr("class", "lineg")
i.exit()
.remove()
i.select(".line")
.datum(function(d) {
return d;
})
.attr("d", function(d) {
return line(d.values)
})
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="500" height="300"></svg>
<br/>
<button onclick="update()">Change</button>
Upvotes: 1