Aldo
Aldo

Reputation: 303

d3.csv vs d3.json: Cannot read property 'length' of undefined using JSON data

Trying to understand mbostock's example (here), I have run in a strange problem:

Using CSV data (loaded with d3.csv()) , everything works perfectly. When using d3.json(), I get "Cannot read property 'length' of undefined using JSON data" and we're talking the same data, with the same data format, just converted using online convertcsv, and the data passes JSONLint validation too.

(I have read similar posts and their relative answer about data being in array using csv and objects in json, but using the native d3.csv() and d3.json() functions, shouldn't the resulting data object be the same?)

The CSV data:

date,price
Jan 2000,1394.46
Feb 2000,1366.42
Mar 2000,1498.58
Apr 2000,1452.43
May 2000,1420.6
Jun 2000,1454.6
Jul 2000,1430.83
Aug 2000,1517.68
Sep 2000,1436.51
Oct 2000,1429.4
Nov 2000,1314.95
Dec 2000,1320.28

The converted JSON:

[
  {
    "date":"Jan 2000",
    "price":1394.46
  },
  {
    "date":"Feb 2000",
    "price":1366.42
  },
  {
    "date":"Mar 2000",
    "price":1498.58
  },
  {
    "date":"Apr 2000",
    "price":1452.43
  },
  {
    "date":"May 2000",
    "price":1420.6
  },
  {
    "date":"Jun 2000",
    "price":1454.6
  },
  {
    "date":"Jul 2000",
    "price":1430.83
  },
  {
    "date":"Aug 2000",
    "price":1517.68
  },
  {
    "date":"Sep 2000",
    "price":1436.51
  },
  {
    "date":"Oct 2000",
    "price":1429.4
  },
  {
    "date":"Nov 2000",
    "price":1314.95
  },
  {
    "date":"Dec 2000",
    "price":1320.28
  }
]

and lastly, the code is:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

svg {
  font: 10px sans-serif;
}

.area {
  fill: steelblue;
  clip-path: url(#clip);
}

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}

</style>
<body>
<script src="..\d3.v3.min.js"></script>
<script>

var margin = {top: 10, right: 10, bottom: 100, left: 40},
    margin2 = {top: 430, right: 10, bottom: 20, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    height2 = 500 - margin2.top - margin2.bottom;

var parseDate = d3.time.format("%b %Y").parse;

var x = d3.time.scale().range([0, width]),
    x2 = d3.time.scale().range([0, width]),
    y = d3.scale.linear().range([height, 0]),
    y2 = d3.scale.linear().range([height2, 0]);

var xAxis = d3.svg.axis().scale(x).orient("bottom"),
    xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
    yAxis = d3.svg.axis().scale(y).orient("left");

var brush = d3.svg.brush()
    .x(x2)
    .on("brush", brushed);

var area = d3.svg.area()
    .interpolate("monotone")
    .x(function(d) { return x(d.date); })
    .y0(height)
    .y1(function(d) { return y(d.price); });

var area2 = d3.svg.area()
    .interpolate("monotone")
    .x(function(d) { return x2(d.date); })
    .y0(height2)
    .y1(function(d) { return y2(d.price); });

var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom);

svg.append("defs").append("clipPath")
    .attr("id", "clip")
  .append("rect")
    .attr("width", width)
    .attr("height", height);

var focus = svg.append("g")
    .attr("class", "focus")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var context = svg.append("g")
    .attr("class", "context")
    .attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");

d3.json("singlestock.json", type, function(error, data) {
//d3.csv("singlestock.csv", type, function(error, data) {
  x.domain(d3.extent(data.map(function(d) { return d.date; })));
  y.domain([price, d3.max(data.map(function(d) { return d.price; }))]);
  x2.domain(x.domain());
  y2.domain(y.domain());

  focus.append("path")
      .datum(data)
      .attr("class", "area")
      .attr("d", area);

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

  focus.append("g")
      .attr("class", "y axis")
      .call(yAxis);

  context.append("path")
      .datum(data)
      .attr("class", "area")
      .attr("d", area2);

  context.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height2 + ")")
      .call(xAxis2);

  context.append("g")
      .attr("class", "x brush")
      .call(brush)
    .selectAll("rect")
      .attr("y", -6)
      .attr("height", height2 + 7);
});

function brushed() {
  x.domain(brush.empty() ? x2.domain() : brush.extent());
  focus.select(".area").attr("d", area);
  focus.select(".x.axis").call(xAxis);
}

function type(d) {
  d.date = parseDate(d.date);
  d.price = +d.price;
  return d;
}

</script>

(nearly 100% from mbostock's example here) In the code, just uncomment the only commented row to switch from CSV to JSON.

-----EDIT--- As per nikosh answer: the problem was fixed in this way:

d3.json("singlestock.json",  function(error, data) {
        data.forEach(function(d) {
        d.date = parseDate(d.date);
        d.price = +d.price;
        d.NAgg = +d.NAgg;
    });

Upvotes: 1

Views: 1454

Answers (1)

nikoshr
nikoshr

Reputation: 33364

Compare the signature of d3.json

d3.json(url[, callback])

and your actual call

d3.json("singlestock.json", type, function(error, data) {... });

You forgot to remove type from your arguments, use

d3.json("singlestock.json", function(error, data) {... })

Upvotes: 2

Related Questions