0

I have seen many examples with d3.csv() callback mappings such as:

var data = raw_data.map(function(d) { return 
    variable1 : +d.variable1,
    variable2 : +d.variable2
});

However I'm trying to figure out how to use map.() for a JSON callback. The reason being is I have a attribute d: expected number, "MaNn", "NaNz" error. This error if I'm not mistaken, is often associated with data being parsed as a string. The JSON looks to be in numbers/floats, but just in case D3 is parsing my data as strings, I want to map it as numbers so I can rule out the parsed as a string culprit from my console log error. So, what I tried was roughly the same as the csv case above, using the unary +:

var json = raw_json.map(function(d)  { return
    xs: +d.xs,
    ys: +d.ys,
    id: +d.id
});

At this point, the error was still there. However I'm not sure if I fully rejected my null hypothesis of string parse error because I'm not totally confident that my JSON data .map() is of the right syntax. I'm kind of in limbo at the moment.

Question: Is my .map() totally wrong? Is there something more I can do to troubleshoot the expected number error?

I realize that JSON files have a wide range of data structures. Here is a screen shot of what my console.log(raw_json) looks like in the console log:

enter image description here

1 Answer 1

1

Your .map() does not match your JSON data. Your JSON consists of one array having one object containing three arrays for id, xs and ys. To convert all those strings to numerical values you need three separate loops:

var obj = raw_json[0];
obj.id = obj.id.map(id => +id);
obj.xs = obj.xs.map(x => +x);
obj.ys = obj.ys.map(y => +y);

Or, preferably, since you do not need to create new arrays while only converting to numbers, you could also do the conversion on the spot using .forEach() instead of .map().

const toNum = (d, i, a) => { a[i] = +d };   // Conversion function

var obj = raw_json[0];
obj.id.forEach(toNum);
obj.xs.forEach(toNum);
obj.ys.forEach(toNum);

Have a look at the following working example:

var raw = `
  [{
    "id": ["1", "2", "3"],
    "xs": ["11", "12", "13"],
    "ys": ["21", "22", "23"]
  }]
`;
var data = JSON.parse(raw);

const toNum = (d, i, a) => { a[i] = +d };   // Conversion function

var obj = data[0];
obj.id.forEach(toNum);
obj.xs.forEach(toNum);
obj.ys.forEach(toNum);

console.dir(data);

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

4 Comments

Would I want to use obj or raw_json for a line generator? .attr('d', lineGenerator(raw_json). I tried both, neither had any errors. Path expects an array right? So I could use raw_json and it will be numbers correct? I went with your const conversion approach.
@ArashHowaida Not directly related to your question, but since you asked for a line generator... You might also want to pass your arrays through d3.zip() to get one array of individual point arrays: d3.zip(obj.id, obj.xs, obj.ys). This will yield [[1, 11, 21], [2, 12, 22], [3, 13, 23]] which can be passed to the line generator and will help simplifying your accessor functions.
@ArashHowaida Expanding on my last comment, this could significantly be simplified by just doing var data = obj.id.map((id, i) => [+id, +obj.xs[i], +obj.ys[i]]); replacing both my above snippet as well as d3.zip() with just one line.
After a few hours of experimenting I couldn't get that last solution (or any of the other ones) to be recognized by my line generator. Although I agree with your assessment that the convert to number issue is resolved, now it's a separate matter. Your approach looks very promising, I'd really appreciate further advice on my new question. I provided more details and uploaded a block.

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.