Data type conversion in d3.js without prior knowledge of property names (determine if string contains only numbers)

In d3.js. I can read a user uploaded CSV file in my web application, for example:

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

      

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

If I knew the names of the properties 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, since this is user-supplied data, there is no way to know the property names in advance. Is there a way to detect that the fields only contain numbers and then change the data type accordingly? Maybe some kind of regex conditional statement or something else?

The examples were adapted from this tutorial.

+4


source to share


2 answers


New answer :

D3 v5.8 introduced a very handy method that makes this task pretty simple: d3.autotype

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>
      

Run codeHide result



( Original answer )

As discussed in the comments , you can use a regular expression to check if a string contains only numbers. Then, if it does, you cast it to a number.

In the next demo I am using <pre>

to store data as I cannot use a d3.csv

function d3.csv

in a stack fragment.

There are three columns in the simulated CSV. One of them,, header3

has numbers. We know this, but the code doesn't do it: it just checks all values ​​with regular expressions and converts strings containing only numbers 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>
      

Run codeHide result


This answers your question, which is to "determine if a string contains only numbers". However, if you want to deal with negative numbers, scientific notation, and floating point numbers, you can drop the regex and use something more elegant:

In JavaScript, NaN

it is not equal to anything, not even to itself. Since using a 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's 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>
      

Run codeHide result


+4


source


I would use parseFloat

(or parseInt

if you know you don't need to care about floats)

function maybeNumber(someString) {
    var result = parseFloat(someString, 10);
    if (isNaN(result)) {
        return someString;
    }
    return result;
}

data = data.map(maybeNumber);

      



This is safer than allowing a forced type on your data.

-1


source







All Articles