santoku
santoku

Reputation: 3447

d3.js how to use radio button result to update chart

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.

enter image description here Anything missing here? Thanks in advance.

Upvotes: 1

Views: 1654

Answers (1)

Gerardo Furtado
Gerardo Furtado

Reputation: 102218

The main problems in your code are these:

  1. You're appending the SVG inside redraw(). Move it outside, append the SVG only once.
  2. 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:

  1. Don't define the scales every time the radio button is clicked. Just change their domains.
  2. You have a band scale here. Therefore, use it for the x and width attributes.
  3. Your CSV has spaces. Remove them.

This is the updated bl.ocks: https://bl.ocks.org/GerardoFurtado/40c4a36d48e6dfaa30f0325f2973098f/fd2f8c76bf3cbaf6b57c34dfc2f00b0d394079ac

Upvotes: 1

Related Questions