stickler
stickler

Reputation: 173

d3 TypeError: Cannot read property 'length' of undefined

Hi I am using a large json file in d3, about 75 KB. It seems to work for the 32 data objects but then I get the error in the console Cannot read property 'length' of undefined. It seems like my json is ok since I put it in http://jsonlint.com/ and it validated. I know similar questions have been asked here but I'm new to d3 so don't know how to modify the code. I think it may have something to do with how d3 is getting the data from my json file.
Here is d3 code in its entirety:

function truncate(str, maxLength, suffix) {
if(str.length > maxLength) {
    str = str.substring(0, maxLength + 1); 
    str = str.substring(0, Math.min(str.length, str.lastIndexOf(" ")));
    str = str + suffix;
}
return str;
}

var margin = {top: 20, right: 200, bottom: 0, left: 20},
    width = 300,
    height = 650;

var start_year = 2004,
    end_year = 2013;

var c = d3.scale.category20c();

var x = d3.scale.linear()
    .range([0, width]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("top");

var formatYears = d3.format("0000");
xAxis.tickFormat(formatYears);

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .style("margin-left", margin.left + "px")
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.json("data.json", function(error, data) {
        if (error) throw error; 

x.domain([start_year, end_year]);
var xScale = d3.scale.linear()
    .domain([start_year, end_year])
    .range([0, width]);

svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + 0 + ")")
    .call(xAxis);

console.log(data.length);   
var len = data.length;
for (var j = 0; j < len; j++) {
    // try{
    var g = svg.append("g").attr("class","journal");

    var circles = g.selectAll("circle")
        .data(data[j]['articles'])
        .enter()
        .append("circle");

    var text = g.selectAll("text")
        .data(data[j]['articles'])
        .enter()
        .append("text");

    var rScale = d3.scale.linear()
        .domain([0, d3.max(data[j]['articles'], function(d) { return d[1]; })])
        .range([2, 9]);

    circles
        .attr("cx", function(d, i) { return xScale(d[0]); })
        .attr("cy", j*20+20)
        .attr("r", function(d) { return rScale(d[1]); })
        .style("fill", function(d) { return c(j); });

    text
        .attr("y", j*20+25)
        .attr("x",function(d, i) { return xScale(d[0])-5; })
        .attr("class","value")
        .text(function(d){ return d[1]; })
        .style("fill", function(d) { return c(j); })
        .style("display","none");

    g.append("text")
        .attr("y", j*20+25)
        .attr("x",width+20)
        .attr("class","label")
        .text(truncate(data[j]['name'],30,"..."))
        .style("fill", function(d) { return c(j); })
        .on("mouseover", mouseover)
        .on("mouseout", mouseout);
    // }
    // catch(err){
    //  console.log(err);
    //  continue;
    // }
};

function mouseover(p) {
    var g = d3.select(this).node().parentNode;
    d3.select(g).selectAll("circle").style("display","none");
    d3.select(g).selectAll("text.value").style("display","block");
}

function mouseout(p) {
    var g = d3.select(this).node().parentNode;
    d3.select(g).selectAll("circle").style("display","block");
    d3.select(g).selectAll("text.value").style("display","none");
}


});


Sample json:

[{"articles":[[2004,25],[2005,25],[2006,26],[2007,31],[2008,20],[2009,26],[2010,19],[2011,18],[2012,24],[2013,17]],"total": 231,"name": " Acta Inf. " }, 
{"articles":[[2008,1]],"total": 1,"name": " nf. " }, 
{"articles":[[2005,27],[2006,30],[2007,27],[2008,75],[2009,31],[2010,34],[2011,46],[2012,35],[2013,60]],"total": 365,"name": " Displays " }, 
{"articles":[[2010,20],[2011,16],[2012,16]],"total": 52,"name": " IJKDB " }, 
{"articles":[[2004,61],[2005,70],[2006,72],[2007,71],[2008,79],[2009,65],[2010,80],[2011,77],[2012,82],[2013,121]],"total": 778,"name": " Computers in Industry " }, 
{"articles":[[2010,1]],"total": 1,"name": " rs in Industry " }, 
{"articles":[[2005,1]],"total": 1,"name": " ry " }, ...

EDIT: no longer getting the error in console, there was something wrong with my JSON..however still not displaying all entries in the visualization, here is my entire JSON file https://api.myjson.com/bins/425wh

EDIT 2: it all displays now! all the data was there but wasn't showing up because the height of the d3 canvas was too small

Upvotes: 1

Views: 747

Answers (1)

Cyril Cherian
Cyril Cherian

Reputation: 32327

The problem is in the last entry. The last entry is an array which is in correct it should have be an object, so your dataset has array within array in the last record. You will need to flatten your data set array.

Add this after fetching the data from AJAX.

data = [].concat.apply([], data);//this will flatten all your array within array into a single array of records,

Edit

Second problem:

I only see a few that actually show up? for example the Journal with name "Artificial Intelligence in Education" does not appear.

The problem is that the svg height is less and the data to be displayed is more so it cuts off after 30 records.

So have a dynamic height like this:

d3.select("body svg").attr("height",len*20.2);//20.2 is approx height of one element

Now height will depend on the data length that needs to displayed.

I have updated the fiddle accordingly

Working code here.

Upvotes: 1

Related Questions