Reputation: 3447
I've read multiple SO answers on how to return values from radio button, but I'm a bit puzzled as to how to use this returned value to update chart.
In this example below, the radio button doesn't update anything, what went wrong here?
<!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>
<div class="chart-container">
<form class="controls">
Scale:
<label>
<label><input type="radio" name="market" value="A" checked>
A</label>
<label><input type="radio" name="market" value="B"> B</label>
</label>
</form>
<svg class="chart js-chart"></svg>
</div>
<script type="text/javascript">
var margin = {top: 20, right: 20, bottom: 30, left: 40},
w = 600 - margin.left - margin.right,
h = 300 - margin.top - margin.bottom;
d3.csv('food.csv', function(error, data) {
if (error) throw error;
// format the data
data.forEach(function(d) {
d.Deliciousness=+d.Deliciousness
});
//radio button
d3.selectAll(("input[name='market']")).on("change", function(){
console.log(this.value)
var data_new=data.filter(d=>(d.Market==this.value));
console.log(data_new);
redraw(data_new);
});
function redraw(data){
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);
svg.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', 20)
.attr('height',d =>h-yScale(d.Deliciousness))
.attr('fill',"blue");
}
})
// });
</script>
</body>
</html>
and the data is:
Market, Food,Deliciousness
A, Apples,9
A, Green Beans,5
A, Bananas,5
B, Apples,4
B, Green Beans,8
B, Bananas,7
And it's only returning a chart with B market, selecting A market doesn't work: it was just blank initially.
then after selecting B, B chart shows, switching back to A, B chart remains and A chart doesn't show.
Anything missing here? Thanks in advance.
Upvotes: 1
Views: 1654
Reputation: 102218
The main problems in your code are these:
redraw()
. Move it outside, append the SVG only once.You don't have an update and enter selections. It should be:
var rect = svg.selectAll('rect')
.data(data);
var rectEnter = rect.enter()
.append('rect')
.merge(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");
Also, it's a good idea having an exit selection.
Minor problems:
x
and width
attributes.This is the updated bl.ocks: https://bl.ocks.org/GerardoFurtado/40c4a36d48e6dfaa30f0325f2973098f/fd2f8c76bf3cbaf6b57c34dfc2f00b0d394079ac
Upvotes: 1