2

I'm trying to use a JSON variable to populate a bar chart, but when I attempt to set the max value of the y domain the code pulls back the wrong value.

var sample_data = {"category":
{"categoryname":"Beverages","num_products":"12"}, 
{"categoryname":"Condiments","num_products":"12"}, 
{"categoryname":"Confections","num_products":"13"},
{"categoryname":"Dairy Products","num_products":"10"}, 
{"categoryname":"Grains/Cereals","num_products":"7"}, 
{"categoryname":"Meat/Poultry","num_products":"6"}, 
{"categoryname":"Produce","num_products":"5"}, 
{"categoryname":"Seafood","num_products":"12"}]};

The code always returns 7, and not 13.

function loadJSONChart(data) {      
            ...                 
            x.domain(data.category.map(function(d) { return d.categoryname; }));
            y.domain([0, d3.max(data.category, function(d) { return d.num_products; })]);
            ...

What am I doing wrong?

Broodmdh
  • 109
  • 1
  • 1
  • 6
  • 1
    Is it returning 7? Try casting as an integer. – FJT May 01 '18 at 18:00
  • 1
    You are comparing strings, `"7"` is a string. Instead coerce to number, the easiest way coerce a string to a number probably is using the [unary +](https://stackoverflow.com/q/9081880/7106086) operator like so: `y.domain([0, d3.max(data.category, function(d) { return +d.num_products; })])`. See also: https://stackoverflow.com/q/20592782/7106086 – Andrew Reid May 01 '18 at 18:04
  • That was it exactly. Thanks for the help! – Broodmdh May 01 '18 at 18:18

1 Answers1

0

The reason behind this is because the numbers you're dealing with aren't actually numbers - they are strings. In this case it's going to use the max based on string comparison (which I imagine would be based on sort orders).

What you want to do is case your data beforehand to be a number. If you're using static data just do the following:

data = data.map(d => ({ ...d, num_products: +d.num_products });

I'd recommend doing this early on with your source data as otherwise you may repeat this operation several times which is wasteful.

If you're requesting the data then you can also format the data on the way in. A typical example (D3 V5) would look like this:

d3.json("...pathToJson")
  .then(data => data.map(d => ({ ...d, num_products: +d.num_products }))
  .then((data) => {
     // Call you render function
  });

Note that you can do the same with previous versions of D3 but they don't use promises, instead they typically take an extra callback into the d3.csv(), d3.json(), d3.tsv() function.

Ian
  • 33,605
  • 26
  • 118
  • 198