lharby
lharby

Reputation: 3265

Uncaught TypeError: n.getMonth is not a function in d3 bar chart

I am getting an error, I suspect with the date objects, from a json file which is being read via d3.

I am basing the code on this example: https://bl.ocks.org/mbostock/1134768

I have modified this to read a json file, rather than a tsv. The function should read in the json, then run a function called type(), which should read the date strings from the json and parse them into date objects.

I have created an example at jsfiddle

My function looks like this:

var dataURL = 'https://api.myjson.com/bins/x9e87';
var timeOfDay = ["Before 03:00","Before 08:00","Before 10:00", "Before 15:00", "Before 17:00","Before 23:59"];
var parseDate = d3.time.format("%d/%m/%Y").parse;

var margin = {top: 20, right: 50, bottom: 30, left: 20},
    width = 500 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var x = d3.scale.ordinal().rangeRoundBands([0, width]);
var y = d3.scale.linear().rangeRound([height, 0]);
var z = d3.scale.category20();

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")
    .tickFormat(d3.time.format("%b"));

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("right");

var svg = d3.select("body").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 + ")");

d3.json(dataURL, function(error, ingestionAmount) {
  if (error) throw error;

  var layers = d3.layout.stack()(timeOfDay.map(function(c) {
    return ingestionAmount.map(function(d) {
      return {x: d.date, y: d[c]};
    });
  }));

  x.domain(layers[0].map(function(d) { return d.x; }));
  y.domain([0, d3.max(layers[layers.length - 1], function(d) { return d.y0 + d.y; })]).nice();

  var layer = svg.selectAll(".layer")
      .data(layers)
      .enter().append("g")
      .attr("class", "layer")
      .style("fill", function(d, i) { return z(i); });

  layer.selectAll("rect")
      .data(function(d) { return d; })
      .enter().append("rect")
      .attr("x", function(d) { return x(d.x); })
      .attr("y", function(d) { return y(d.y + d.y0); })
      .attr("height", function(d) { return y(d.y0) - y(d.y + d.y0); })
      .attr("width", x.rangeBand() - 1);

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

  svg.append("g")
      .attr("class", "axis axis--y")
      .attr("transform", "translate(" + width + ",0)")
      .call(yAxis);

      type();
});

function type(d) {
  d.date = parseDate(d.date);
  timeOfDay.forEach(function(c) { d[c] = +d[c]; });
  return d;
}

My json is straightforward (the full file is available here https://api.myjson.com/bins/x9e87)

[  
   {  
      "date":"11/11/2017",
      "Before 03:00":31,
      "Before 08:00":5,
      "Before 10:00":44,
      "Before 15:00":18,
      "Before 17:00":98,
      "Before 23:59":12
   },
   {  
      "date":"12/11/2017",
      "Before 03:00":30,
      "Before 08:00":3,
      "Before 10:00":67,
      "Before 15:00":4,
      "Before 17:00":24,
      "Before 23:59":33
   },
{ ///
]

I thought perhaps d3 was specific about date formats, so I added hours, minutes and seconds, but this made no difference. I also found this Q/A which suggests changing the d3 scale function. Again this did not work. I am parsing the date in the way that d3 should expect "%d/%m/%Y" it so I cannot work out what the issue is.

Upvotes: 0

Views: 378

Answers (1)

Shashank
Shashank

Reputation: 5660

Here is a demo: JS FIDDLE

The way the "type" function is being called is incorrect. If you debug the chart at https://bl.ocks.org/mbostock/1134768, you'll see that every element from the array "crimea" is parsed and formatted in the type function.

Now that d3.json has no accessor argument where in you can pass type function as we can do in d3.csv(function(<filename>, type, callback){}) , we'll have to do it manually.

Relevant code:

Parse every element of array:

ingestionAmount.forEach(function(d) {
  type(d);
});

Hope this helps. :)

Upvotes: 2

Related Questions