1

I am trying to dynamically add graphs to my webpage using for loop. Each graph in a separate row of a table. But only the last graph is being displayed. For others, the g element is not getting added.

This is the hierarchy of last graph(Successful one) :- tr -> td -> svg -> g(transform) -> g(x axis) -> g(y axis) -> path

and for the other, it is :- tr -> td -> svg -> g(transform)

On further analysis, I found that in the successful graph, path, x and y axis are added as many number of times, as the loop is running.

here is my code :-

// Define the line
    var valueline = d3.svg.line()
        .x(function(d) { return x(d[xA]); })
        .y(function(d) { return y(d[yA]); });

    for(var i = 0; i < yAV.length; i++){
        var yA = yAV[i];

    // Adds the svg canvas
    chart1 = d3.select("#graph table")
    .append("tr")
    .append("td")
    .append("svg")
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
    .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

    // Get the data

    d3.json("graphdata.json", function(error, data) {
          data.forEach(function(d) {
            d[xA] = +d[xA];
            d[yA] = +d[yA];
          });

          x.domain(d3.extent(data, function(d) { return d[xA]; }));
          y.domain(d3.extent(data, function(d) { return d[yA]; }));


        // Add the X Axis
        chart1.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);


        // Add the Y Axis
        chart1.append("g")
            .attr("class", "y axis")
            .call(yAxis);  

        // Add the valueline path.
        chart1.append("path")
            .attr("class", "line")
            .attr("d", valueline(data));


    });

    }

Please help me out solving this problem.

LIQvID
  • 147
  • 1
  • 10
  • a small update - I tried adding the x and y axis above the JSON call, and then, the x and y axis are coming for each iteration, but not the graph – LIQvID Mar 22 '16 at 11:36

1 Answers1

0

the callback in d3.json is asynchronous. You're expecting it to run like this:

loop iteration 1:
  chart1 = add new svg/g 
  d3.json add stuff to chart1
loop iteration 2:
  chart1 = add new svg/g
  d3.json add stuff to chart1
loop iteration 3: etc

but the d3.json callback only runs when the data has been loaded, and in browser-based javascript will only run when javascript has finished executing its current code (the whole loop) - see Javascript asynchronous execution: will a callback interrupt running code?.

So what you'll get is:

loop iteration 1:
  chart1 = add svg/g 
loop iteration 2:
  chart1 = add svg/g
loop iteration3: etc
end of loop
then
a set of d3.json callbacks adding stuff to last value of chart1

and that last line is why you're only seeing the elements within the d3.json callback added to one svg

To fix it you'll need to add a counter inside the d3.json callback that increments on each run to access the right index of svg element and data set (thought it seems to be the same dataset each time?)

Community
  • 1
  • 1
mgraham
  • 6,147
  • 1
  • 21
  • 20
  • Thanks for your answer, Yes, the dataset is same each time, but the X and Y axes vary each time. Also, how to get the index of svg element? Can u plz share a sample code or edit my code for the same? Thanks again @mgraham – LIQvID Mar 22 '16 at 11:53
  • Ok I was able to do it. Thanks to this post http://stackoverflow.com/questions/15261313/how-do-i-load-json-data-synchronously-with-d3-js – LIQvID Mar 22 '16 at 12:08
  • This is one way of doing it --> http://jsfiddle.net/78ohabsk/1/ . Basically .selectAll the svgs and filter it to one using a counter variable. There's probably better ways. – mgraham Mar 22 '16 at 12:14
  • Wow..that really helped.. U r a rockstar buddy :) thanx a ton @mgraham – LIQvID Mar 22 '16 at 12:24