1

Originally, when the data was a simple array like this [21, 3, 5, 21, 15] it worked just fine. But, when I attempt to use an array of objects I get the following error and I don't know how to fix it.

Error: <rect> attribute y: Expected length, "NaN".

When I stop using the console debugger at return yScale(d.Amount); I see it read in the data but with the error. The return line right above it return h - yScale(d.Amount); produces no error.

var myData = [{
  'Name': 'User1',
  'Amount': 21
}, {
  'Name': 'User2',
  'Amount': 3
}, {
  'Name': 'User3',
  'Amount': 5
}, {
  'Name': 'User4',
  'Amount': 21
}, {
  'Name': 'User5',
  'Amount': 15
}];
//Width and height
var w = 240;
var h = 250;
var yScale = null;

function draw(initialData) {
  var xScale = d3.scale.ordinal()
    .domain(d3.range(initialData.length))
    .rangeRoundBands([0, w], 0.05);

  yScale = d3.scale.linear()
    .domain([0, d3.max(initialData)])
    .range([0, h]);

  //Create SVG element
  var svg = d3.select("#chart")
    .append("svg")
    .attr("width", w)
    .attr("height", h);

  var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom")
    .ticks(5);

  var yAxis = d3.svg.axis()
    .scale(yScale);

  svg.selectAll("rect")
    .data(initialData)
    .enter()
    .append("rect")
    .attr("x", function(d, i) {
      return xScale(i);
    })
    .attr("y", function(d) {
      return h - yScale(d.Amount);
    })
    .attr("width", xScale.rangeBand())
    .attr("height", function(d) {
      return yScale(d.Amount);
    })
    .attr("fill", "steelblue");

  svg.selectAll("text")
    .data(initialData)
    .enter()
    .append("text")
    .text(function(d) {
      return d.Amount;
    })
    .attr("text-anchor", "middle")
    .attr("x", function(d, i) {
      return xScale(i) + xScale.rangeBand() / 2;
    })
    .attr("y", function(d) {
      return h - yScale(d.Amount) + 14;
    })
    .attr("font-family", "sans-serif")
    .attr("font-size", "11px")
    .attr("fill", "white");

  var xAxisGroup = svg.append("g")
    .attr("transform", "translate(0," + 248 + ")")
    .style("stroke-width", "1px")
    .call(xAxis);
}

function update(newData) {
  yScale.domain([0, d3.max(newData)]);

  var rects = d3.select("#chart svg")
    .selectAll("rect")
    .data(newData);

  // enter selection
  rects
    .enter().append("rect");

  // update selection
  rects
    .transition()
    .duration(300)
    .attr("y", function(d) {
      return h - yScale(d.Amount);
    })
    .attr("height", function(d) {
      return yScale(d.Amount);
    })

  // exit selection
  rects
    .exit().remove();

  var texts = d3.select("#chart svg")
    .selectAll("text")
    .data(newData);

  // enter selection
  texts
    .enter().append("rect");

  // update selection
  texts
    .transition()
    .duration(300)
    .attr("y", function(d) {
      return h - yScale(d.Amount) + 14;
    })
    .text(function(d) {
      return d.Amount;
    })

  // exit selection
  texts
    .exit().remove();
}

window.onload = draw(myData);

var newData = [{
  'Name': 'User1',
  'Amount': 11
}, {
  'Name': 'User2',
  'Amount': 13
}, {
  'Name': 'User3',
  'Amount': 5
}, {
  'Name': 'User4',
  'Amount': 7
}, {
  'Name': 'User5',
  'Amount': 5
}];
d3.select("#update").on("click", function() {
  update(newData);
})

1 Answer 1

1

The problem is the yScale domain.

When you had just an array you could pass it to d3.max:

yScale.domain([0, d3.max(newData)])

However, now that you have an array of objects, you have to define which property you want d3.max to use:

.domain([0, d3.max(initialData, function(d){
    return d.Amount
})])

Here is your code with that change only:

 var myData = [{
   'Name': 'User1',
   'Amount': 21
 }, {
   'Name': 'User2',
   'Amount': 3
 }, {
   'Name': 'User3',
   'Amount': 5
 }, {
   'Name': 'User4',
   'Amount': 21
 }, {
   'Name': 'User5',
   'Amount': 15
 }];
 //Width and height
 var w = 240;
 var h = 250;
 var yScale = null;

 function draw(initialData) {
   var xScale = d3.scale.ordinal()
     .domain(d3.range(initialData.length))
     .rangeRoundBands([0, w], 0.05);

   yScale = d3.scale.linear()
     .domain([0, d3.max(initialData, function(d){return d.Amount})])
     .range([0, h]);

   //Create SVG element
   var svg = d3.select("body")
     .append("svg")
     .attr("width", w)
     .attr("height", h);

   var xAxis = d3.svg.axis()
     .scale(xScale)
     .orient("bottom")
     .ticks(5);

   var yAxis = d3.svg.axis()
     .scale(yScale);

   svg.selectAll("rect")
     .data(initialData)
     .enter()
     .append("rect")
     .attr("x", function(d, i) {
       return xScale(i);
     })
     .attr("y", function(d) {
       return h - yScale(d.Amount);
     })
     .attr("width", xScale.rangeBand())
     .attr("height", function(d) {
       return yScale(d.Amount);
     })
     .attr("fill", "steelblue");

   svg.selectAll("text")
     .data(initialData)
     .enter()
     .append("text")
     .text(function(d) {
       return d.Amount;
     })
     .attr("text-anchor", "middle")
     .attr("x", function(d, i) {
       return xScale(i) + xScale.rangeBand() / 2;
     })
     .attr("y", function(d) {
       return h - yScale(d.Amount) + 14;
     })
     .attr("font-family", "sans-serif")
     .attr("font-size", "11px")
     .attr("fill", "white");

   var xAxisGroup = svg.append("g")
     .attr("transform", "translate(0," + 248 + ")")
     .style("stroke-width", "1px")
     .call(xAxis);
 }

 function update(newData) {
   yScale.domain([0, d3.max(newData)]);

   var rects = d3.select("#chart svg")
     .selectAll("rect")
     .data(newData);

   // enter selection
   rects
     .enter().append("rect");

   // update selection
   rects
     .transition()
     .duration(300)
     .attr("y", function(d) {
       return h - yScale(d.Amount);
     })
     .attr("height", function(d) {
       return yScale(d.Amount);
     })

   // exit selection
   rects
     .exit().remove();

   var texts = d3.select("#chart svg")
     .selectAll("text")
     .data(newData);

   // enter selection
   texts
     .enter().append("rect");

   // update selection
   texts
     .transition()
     .duration(300)
     .attr("y", function(d) {
       return h - yScale(d.Amount) + 14;
     })
     .text(function(d) {
       return d.Amount;
     })

   // exit selection
   texts
     .exit().remove();
 }

 window.onload = draw(myData);

 var newData = [{
   'Name': 'User1',
   'Amount': 11
 }, {
   'Name': 'User2',
   'Amount': 13
 }, {
   'Name': 'User3',
   'Amount': 5
 }, {
   'Name': 'User4',
   'Amount': 7
 }, {
   'Name': 'User5',
   'Amount': 5
 }];
 d3.select("#update").on("click", function() {
   update(newData);
 })
<script src="https://d3js.org/d3.v3.min.js"></script>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.