Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert data types in d3.js without prior knowledge of property names (detect if a string contains only digits)

In d3.js. I can read in a user-uploaded CSV file in my web app like this:

d3.csv("upload.csv", function(data) {
  console.log(data[0]);
});

This results in everything being read in as a string. However, I need to be able to treat numeric data types as numbers.

If I knew the property names ahead of time, I could do something like this:

d3.csv("upload.csv", function(data) {
  data.forEach(function(d) {
    d.population = +d.population;
    d["land area"] = +d["land area"];
  });
  console.log(data[0]);
});

However, as this is user-provided data, there's no way to know the property names ahead of time. Is there a way to detect that the fields only contain numbers, then change the data type accordingly? Perhaps some sort of conditional statement with a regex test or something?

The examples were adapted from this tutorial.

like image 392
Hack-R Avatar asked Oct 17 '22 14:10

Hack-R


1 Answers

New Answer:

D3 v5.8 introduced the very handy method d3.autotype, which makes this task quite easy:

var data = d3.csvParse(d3.select("#csv").text(), d3.autoType);

console.log(data);
pre {
  display: none;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<pre id="csv">header1,header2,header3
foo,foo2,1212
bar,bar2,2345
baz,baz2,7623</pre>

(Original Answer)

As discussed in the comments, you can use a regex to check if the string contains only digits. Then, if it does, you coerce it to a number.

In the following demo I'm using a <pre> to store the data, since I cannot use the actual d3.csv function in the Stack snippet.

In the simulated CSV there are three columns. One of them, header3, has numbers. We know that, but the code doesn't: it just check all values using the regex and coerce the strings containing only digits to numbers.

var data = d3.csvParse(d3.select("#csv").text());

data.forEach(function(d) {
  for (var key in d) {
    if (/^\d+$/.test(d[key])) {
      d[key] = +d[key]
    }
  }
});

console.log(data);
pre {
  display: none;
  }
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">header1,header2,header3
foo,foo2,1212
bar,bar2,2345
baz,baz2,7623</pre>

This addresses your question, which is "detect if a string contains only digits". However, if you want to deal with negative numbers, scientific notation and floats as well, you can drop the regex and use something way more elegant:

In JavaScript, NaN is not equal to anything, not even to itself. Since using the unary operator with something that is not a number returns NaN, you can simply do:

if (+d[key]===+d[key]) {
  d[key] = +d[key]
}

Here is another demo, with negatives, floats and scientific notation:

var data = d3.csvParse(d3.select("#csv").text());

data.forEach(function(d) {
  for (var key in d) {
    if (+d[key]===+d[key]) {
      d[key] = +d[key]
    }
  }
});

console.log(data);
pre {
  display: none;
  }
<script src="https://d3js.org/d3.v4.min.js"></script>
<pre id="csv">header1,header2,header3
foo,foo2,12.12
bar,bar2,-2345
baz,baz2,2.4e6</pre>
like image 184
Gerardo Furtado Avatar answered Oct 30 '22 13:10

Gerardo Furtado