Reputation: 21
I am creating a horizontal bar chart that shows data from a CSV file dynamically. I am getting an extra space where another value would be, but without any data. I only want the top 10 values(students) plus keys(counties) and it looks like it adds one.
As you can see it adds a space and a small rect at the top. I just want to remove both.
// Parse Data
d3.csv("FA18_geographic.csv", function(data) {
data.sort(function(a,b) {
return d3.descending(+a.students, +b.students);
});
// find max county
var max = d3.max(data, function(d) { return +d.students;} );
var map = d3.map(data, function(d){return d.students; });
pmax = map.get(max);
// Add X axis
var x = d3.scaleLinear()
.domain([0, +pmax.students+500])
.range([ 0, width]);
svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "translate(-10,0)rotate(-45)")
.style("text-anchor", "end");
// Y axis
var count = 0
var y = d3.scaleBand()
.range([ 0, height ])
.domain(
data.map(function(d) { //only show top 10 counties
count = count+1
if (count<=10){
return d.county;
}})
)
.padding(.3);
svg.append("g")
.call(d3.axisLeft(y));
//Bars //Something must be wrong in here???
svg.selectAll("rect.bar")
.data(data)
.enter()
.append("rect")
.attr("x", x(0) )
.attr("y", function(d) { return y(d.county); })
.attr("width", function(d) { return x(d.students); })
.attr("height", y.bandwidth() )
.attr("fill", "#79200D");
});
</script>
Upvotes: 1
Views: 87
Reputation: 102198
Your problem lies here:
.domain(data.map(function(d) { //only show top 10 counties
count = count + 1
if (count <= 10) {
return d.county;
}
}))
The issue here has nothing to do with D3, that's a JavaScript issue: you cannot skip interactions using Array.prototype.map
.
Let's show this with the basic demo below, in which we'll try to return the item only if count
is less than 5:
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let count = -1;
const domain = data.map(function(d) {
count += 1;
if (count < 5) {
return d
};
});
console.log(domain)
As you see, it will return several undefined
. You only see one empty tick because D3 band scale treats all those values as a single undefined
(domain values in band scales are unique).
There are several solutions here. You can, for instance, use Array.prototype.reduce
:
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let count = -1;
const domain = data.reduce(function(acc, curr) {
count += 1;
if (count < 5) {
acc.push(curr)
};
return acc;
}, []);
console.log(domain)
Alternatively, you can use a filter
after your map
, or even a forEach
to populate the array.
Finally, some tips:
count
, since Array.prototype.map
has an index (the second argument), just like Array.prototype.reduce
(the third argument).count = count + 1
, just do count += 1
;count
as -1
instead of 0
. Upvotes: 1