Reputation: 81
There are many cases online how to plot couple of lines in d3 if you add svg object only once, such as
svg.selectAll("line")
.data(dataset)
.enter().append("line")
.style("stroke", "black") // colour the line
.attr("x1", function(d) { console.log(d); return xScale(d.x1); })
.attr("y1", function(d) { return yScale(d.y1); })
.attr("x2", function(d) { return xScale(d.x2); })
.attr("y2", function(d) { return yScale(d.y2); });
This plot create one line. I want to create many different lines in an array smth like
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
for (a_ind=1; a_ind<3; a_ind++){
dataset_a=dataset.filter(function(d) { return (d.a==a_ind)})
svg.selectAll("line")
.data(dataset_a) - //!!! using new dataset in each cycle
.enter().append("line")
.style("stroke", "black") // colour the line
.attr("x1", function(d) { console.log(d); return xScale(d.x1); })
.attr("y1", function(d) { return yScale(d.y1); })
.attr("x2", function(d) { return xScale(d.x2); })
.attr("y2", function(d) { return yScale(d.y2); });
}
I was told it's impossible. Or maybe there is the way? And also how to access then line from dataset_a if i want to delete it with the click of the mouse?
Upvotes: 1
Views: 2284
Reputation: 102194
Well, if you want to plot lines, I suggest that you append...<line>
s!
The thing with a D3 enter selection is quite simple: the number of appended elements is the number of objects in the data array that doesn't match any element.
So, you just need a data array with several objects. For instance, let's create 50 of them:
var data = d3.range(50).map(function(d) {
return {
x1: Math.random() * 300,
x2: Math.random() * 300,
y1: Math.random() * 150,
y2: Math.random() * 150,
}
});
And, as in the below demo I'm selecting null
, all of them will be in the enter selection. Here is the demo:
var svg = d3.select("svg");
var data = d3.range(50).map(function(d) {
return {
x1: Math.random() * 300,
x2: Math.random() * 300,
y1: Math.random() * 150,
y2: Math.random() * 150,
}
});
var color = d3.scaleOrdinal(d3.schemeCategory20);
var lines = svg.selectAll(null)
.data(data)
.enter()
.append("line")
.attr("x1", function(d) {
return d.x1
})
.attr("x2", function(d) {
return d.x2
})
.attr("y1", function(d) {
return d.y1
})
.attr("y2", function(d) {
return d.y2
})
.style("stroke", function(_, i) {
return color(i)
})
.style("stroke-width", 1);
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Finally, a tip: as this is JavaScript you can use for
loops anywhere you want. However, do not use for
loops to append elements in a D3 code. It's unnecessary and not idiomatic.
That being said, whoever told you that it is impossible was wrong, it's clearly possible. Here is a demo (but don't do that, it's a very cumbersome and ugly code):
var svg = d3.select("svg");
var data = d3.range(50).map(function(d, i) {
return {
x1: Math.random() * 300,
x2: Math.random() * 300,
y1: Math.random() * 150,
y2: Math.random() * 150,
id: "id" + i
}
});
var color = d3.scaleOrdinal(d3.schemeCategory20);
for (var i = 0; i < data.length; i++) {
var filteredData = data.filter(function(d) {
return d.id === "id" + i
});
var lines = svg.selectAll(null)
.data(filteredData)
.enter()
.append("line")
.attr("x1", function(d) {
return d.x1
})
.attr("x2", function(d) {
return d.x2
})
.attr("y1", function(d) {
return d.y1
})
.attr("y2", function(d) {
return d.y2
})
.style("stroke", function() {
return color(i)
})
.style("stroke-width", 1);
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
Upvotes: 2
Reputation: 2550
I would do something like this. Make each data set (1 data set per line), an array inside the final data array .enter().append()
will then work properly. To remove the line on click, I added an event handler that will select the line just clicked and remove it.
var data = [[dataset_a], [dataset_b], [dataset_c], [dataset_d], [dataset_e]];
var xValue = function(d){return d.x;}
var yValue = function(d){return d.y;}
var lineFunction = d3.line()
.x(function(d) { return xScale(xValue(d)); })
.y(function(d) { return yScale(yValue(d)); });
var lines = d3.select("svg").selectAll("path")
lines.data(data)
.enter().append("path")
.attr("d", lineFunction)
.on("click", function(d){
d3.select(this).remove();
});
Upvotes: 1