Reputation: 3427
I tried to plot rectangles/bars on top of another layer of shorter&fatter rectangles, but the results are unexpected - only one layer is shown:
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
w = 600 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var data = [{
"Food": "Apples",
"Deliciousness": 9,
"new": 4
}, {
"Food": "Green Beans",
"Deliciousness": 5,
"new": 4
}, {
"Food": "Egg Salad Sandwich",
"Deliciousness": 4,
"new": 4
}, {
"Food": "Cookies",
"Deliciousness": 10,
"new": 4
}, {
"Food": "Liver",
"Deliciousness": 2,
"new": 4
}, ];
// format the data
data.forEach(function(d) {
d.Deliciousness = +d.Deliciousness;
});
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.top + ")");
var xScale = d3.scaleBand()
.domain(d => d.Food)
.range([0, w])
.paddingInner(0.2);
xScale.domain(data.map(function(d) {
return d.Food;
}));
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.Deliciousness)])
.rangeRound([h, 0]);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
var chartgroup = svg.append("g");
chartgroup.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => margin.left + i * w / data.length)
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth())
.attr('height', d => h - yScale(d.Deliciousness))
.attr('fill', "blue");
chartgroup.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => margin.left + i * w / data.length)
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth() / 2)
.attr('height', d => h - yScale(d.Deliciousness) / 2)
.attr('fill', "yellow");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://d3js.org/d3.v4.min.js"></script>
<meta charset="utf-8">
<title>D3: Loading data from a CSV file</title>
</head>
<body>
<!-- <p>click to see changes</p> -->
</body>
</html>
I added a group too but that doesn't solve the issue.
Am I missing something here?
chartgroup.selectAll('rect')
.data(data)
.enter()
.append('rect')
.attr('x',(d,i) => margin.left + i*w/data.length)
.attr('y',d=>yScale(d.Deliciousness))
.attr('width', xScale.bandwidth()/2)
.attr('height',d =>h-yScale(d.Deliciousness)/2)
.attr('fill',"yellow");
Any advice?
Upvotes: 1
Views: 246
Reputation: 102194
When you do this for the second time...
chartgroup.selectAll('rect')
... you're selecting elements already painted in that SVG. Therefore, your second enter selection is empty. Let's prove it:
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
w = 600 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var data = [{
"Food": "Apples",
"Deliciousness": 9,
"new": 4
}, {
"Food": "Green Beans",
"Deliciousness": 5,
"new": 4
}, {
"Food": "Egg Salad Sandwich",
"Deliciousness": 4,
"new": 4
}, {
"Food": "Cookies",
"Deliciousness": 10,
"new": 4
}, {
"Food": "Liver",
"Deliciousness": 2,
"new": 4
}, ];
// format the data
data.forEach(function(d) {
d.Deliciousness = +d.Deliciousness;
});
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.top + ")");
var xScale = d3.scaleBand()
.domain(d => d.Food)
.range([0, w])
.paddingInner(0.2);
xScale.domain(data.map(function(d) {
return d.Food;
}));
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.Deliciousness)])
.rangeRound([h, 0]);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
var chartgroup = svg.append("g");
chartgroup.selectAll("rect")
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => margin.left + i * w / data.length)
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth())
.attr('height', d => h - yScale(d.Deliciousness))
.attr('fill', "blue");
var secondSelection = chartgroup.selectAll("rect")
.data(data)
.enter()
.append('rect')
.attr('x', (d, i) => margin.left + i * w / data.length)
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth() / 2)
.attr('height', d => h - yScale(d.Deliciousness) / 2)
.attr('fill', "yellow");
console.log("Enter selection size is: " + secondSelection.size())
<script src="https://d3js.org/d3.v4.min.js"></script>
Instead of that (provided that you don't plan to have an update selection), select something that doesn't exist, like null
:
chartgroup.selectAll(null)
To better understand why (and sometimes why not) selecting null
have a look here: Selecting null: what is the reason of using 'selectAll(null)' in D3.js?
Here is your code with that change:
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 40
},
w = 600 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
var data = [{
"Food": "Apples",
"Deliciousness": 9,
"new": 4
}, {
"Food": "Green Beans",
"Deliciousness": 5,
"new": 4
}, {
"Food": "Egg Salad Sandwich",
"Deliciousness": 4,
"new": 4
}, {
"Food": "Cookies",
"Deliciousness": 10,
"new": 4
}, {
"Food": "Liver",
"Deliciousness": 2,
"new": 4
}, ];
// format the data
data.forEach(function(d) {
d.Deliciousness = +d.Deliciousness;
});
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," +
margin.top + ")");
var xScale = d3.scaleBand()
.range([0, w])
.paddingInner(0.2)
.domain(data.map(function(d) {
return d.Food;
}));
var xAxis = d3.axisBottom()
.scale(xScale)
.ticks(5);
var yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.Deliciousness)])
.rangeRound([h, 0]);
var yAxis = d3.axisLeft()
.scale(yScale)
.ticks(5);
var chartgroup = svg.append("g");
chartgroup.selectAll(null)
.data(data)
.enter()
.append('rect')
.attr('x', d => xScale(d.Food))
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth())
.attr('height', d => h - yScale(d.Deliciousness))
.attr('fill', "blue");
chartgroup.selectAll(null)
.data(data)
.enter()
.append('rect')
.attr('x', d => xScale(d.Food))
.attr('y', d => yScale(d.Deliciousness))
.attr('width', xScale.bandwidth() / 2)
.attr('height', d => h - yScale(d.Deliciousness) / 2)
.attr('fill', "yellow");
<script src="https://d3js.org/d3.v4.min.js"></script>
Upvotes: 2