0

Here I have a strange problem, I have a data table of the form:

[{grade:"a", count:1000},
{grade:"b", count:935},
.....]

but when I use the map function :

var v = data.map(function (d) { return d.count; });
console.log(v);

table v is found with the values ​​{0,0,0,0,0} If anyone has an idea where the problem may come from, I'm interested.

var svg = d3.select("svg"),
    margin = { top: 20, right: 20, bottom: 30, left: 40 },
    x = d3.scaleBand().padding(0.1),
    y = d3.scaleLinear();

var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

g.append("g")
    .attr("class", "axis axis--x");

g.append("g")
    .attr("class", "axis axis--y");

g.append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", "0.71em")
    .attr("text-anchor", "end")
/*.text("Count of Product")*/;

var dm = data_manager();
var data = dm.load_histo_grade_data();

console.log(data);

x.domain(data.map(function (d) { return d.grade; }));
var v = data.map(function (d) { return d.count; });
console.log(v);
y.domain([0, d3.max(data.map(function (d) { return d.count; }))]);

draw(data);

function draw(theData) {

    var margin = {top: 10, right: 30, bottom: 30, left: 40},
	width = 300 - margin.left - margin.right,
	height = 200 - margin.top - margin.bottom;

    x.rangeRound([0, width]);
    y.rangeRound([height, 0]);

    g.select(".axis--x")
	.attr("transform", "translate(0," + height + ")")
	.call(d3.axisBottom(x));

    
    g.select(".axis--y")
	.call(d3.axisLeft(y));

    // ENTER
    g.selectAll(".bar")
	.data(theData)
	.enter().append("rect")
	.attr("class", "bar")
	.attr("x", function (d) { return x(d.grade); })
	.attr("y", function (d) {
	    return y(d.count); })
	.attr("width", x.bandwidth())
	.attr("height", function (d) { return height - y(d.count); })
	.attr("fill", function(d) { return color_nutriscore_grade(d.grade); } );
}

Edit : The code for the function data_manager and load_histo_grade_data

function data_manager(){
    var dm = {};
    dm.filter = {
	WORLD:0,
	REGION:1
    };
    dm.choosen_filter = dm.filter.WORLD;
    dm.choosen_region = "Europe";
    dm.accept = function(row){
	return true;
    };
    dm.load_histo_grade_data = function(){
	data_to_update = [
	    {grade:"a", count:0.0},
	    {grade:"b", count:0.0},
	    {grade:"c", count:0.0},
	    {grade:"d", count:0.0},
	    {grade:"e", count:0.0}
	];
	d3.tsv("../tsv/hypotesis.tsv", function(error, data){
	    if(error) throw error;
	    var tmp = {
		"a":0,
		"b":1,
		"c":2,
		"d":3,
		"e":4,
	    };
	    for(var i = 1; i<data.length; i++){
		idx = tmp[data[i].grade];
		var v = data_to_update[idx].count;
		data_to_update[idx].count = (v + 1);
	    }
	});
	return data_to_update;
    };
    dm.load = function(){
	dm.load_histo_grade_data();
    }
    return dm;
}

function color_nutriscore_grade(grade){
    switch(grade) {
    case '':  return d3.rgb(191, 191, 191);
    case 'a': return d3.rgb(  0, 191,   0);
    case 'b': return d3.rgb(115, 255,   0);
    case 'c': return d3.rgb(255, 204,   0);
    case 'd': return d3.rgb(255, 102,   0);
    case 'e': return d3.rgb(255,  25,   0);
    };
}

10
  • 4
    The problem is likely caused by the array not looking like you think it looks. Commented Dec 26, 2018 at 19:08
  • 3
    Is load_histo_grade_data() asynchronous? Commented Dec 26, 2018 at 19:10
  • The output for the consle log is : (5) […] ​0: Object { grade: "a", count: 1009 } ​1: Object { grade: "b", count: 935 } ​2: Object { grade: "c", count: 1514 } ​3: Object { grade: "d", count: 2198 } ​4: Object { grade: "e", count: 1690 } ​length: 5 <prototype>: [] Commented Dec 26, 2018 at 19:15
  • 2
    @litsubzu you can't necessarily trust that. Commented Dec 26, 2018 at 19:24
  • 3
    d3.tsv looks like it is asynchronous, that's where your problem is. Commented Dec 26, 2018 at 20:01

1 Answer 1

2

The problem here is that d3.tsv() is asynchronous, meaning it will run your callback "later". So you're returning the initial value of data_to_update (with all grades 0) from dm.load_histo_grade_data(), then later it is being populated with the correct values.

The reason your call to console.log(data) is outputting the populated array is because console.log has the fancy feature of displaying a live object, meaning it the object changes after it was logged, what you see in the console will change too.

The fix is to pass a callback into dm.load_histo_grade_data() instead of waiting for it to return, like so:

// In data_manager()
dm.load_histo_grade_data = function(callback){
    data_to_populate = [
        {grade:"a", count:0.0},
        {grade:"b", count:0.0},
        {grade:"c", count:0.0},
        {grade:"d", count:0.0},
        {grade:"e", count:0.0}
    ];
    d3.tsv("../tsv/hypotesis.tsv", function(error, data){
        if(error) throw error;
        var tmp = {
            "a":0,
            "b":1,
            "c":2,
            "d":3,
            "e":4,
        };
        for (var i = 1; i<data.length; i++){
            idx = tmp[data[i].grade];
            var v = data_to_populate[idx].count;
            data_to_populate[idx].count = (v + 1);
        }
        callback(data_to_populate)
    });
};

You can then use this as follows:

var dm = data_manager();
dm.load_histo_grade_data(function(data) {
    console.log(data);

    x.domain(data.map(function (d) { return d.grade; }));
    var v = data.map(function (d) { return d.count; });
    console.log(v);
    y.domain([0, d3.max(data.map(function (d) { return d.count; }))]);

    draw(data);
});

Side note: You should use camelCase instead of snake_case in JavaScript.

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.