Search code examples
javascriptd3.jscolorsdata-visualizationheatmap

D3.js Heatmap colors based on variable value instead of value for the whole table


I want to create a heatmap which shows the heat/color based on the value of one variable over all groups but not over all variables. Currently I have the following, where the color is based on the value over all values in the map: enter image description here

Thats why almost everything is yellow because the Household net wealth in Luxembourg is just to high. My code for the rectangles is the following:

// Color Scale
var myColor = d3.scaleSequential()
    .interpolator(d3.interpolateViridis)
    .domain([d3.max(data, d=>d.value),d3.min(data, d=>d.value)]);

// add the squares
svg.selectAll()
    .data(data, function (d) { return d.Country + ':' + d.variable; })
    .enter()
    .append("rect")
    .attr("x", function (d) { return x(d.Country) })
    .attr("y", function (d) { return y(d.variable) })
    .attr("rx", 4)
    .attr("ry", 4)
    .attr("width", x.bandwidth())
    .attr("height", y.bandwidth())
    .style("fill", function (d) { return myColor(d.value) })
    .style("stroke-width", 4)
    .style("stroke", "none")
    .style("opacity", 0.8)
    .on("mouseover", mouseover)
    .on("mousemove", mousemove)
    .on("mouseleave", mouseleave)
}

My data is in long format like this:

Country Variable Value
Australia Var 1 Value 1
Australia Var 2 Value 2
... ... ...
Australia Var 24 Value 24
Austria Var 1 Value 25
... ... ...
South Africa Var 24 Value 960

Do you have any ideas of how to change this so this would work? I could also transform the data.

Thanks you so much for your help and have great Tuesday!


Solution

  • I changed the data I am supplying to the front end, by adding two columns: one column regarding the minimum value of the variable over all groups/countries and one column regarding the maximum value of the variable over all groups/countries. My dataset now looks the following way:

    Country Variable Value min max
    Australia Var 1 Value 1 Min(Var1) Max(Var1)
    Australia Var 2 Value 2 Min(Var2) Max(Var2)
    ... ... ... ... ...
    Australia Var 24 Value 24 Min(Var24) Max(Var24)
    Austria Var 1 Value 25 Min(Var1) Max(Var1)
    ... ... ... ... ...
    South Africa Var 24 Value 960 Min(Var24) Max(Var24)

    By including a function which gives me the color variable based on the current variables min and max value I changed the code to the following:

    //Color scale function
    function colorPerVariable(minimun, maximum, value) {
            var myColor = d3.scaleSequential()
                .interpolator(d3.interpolateViridis)
                .domain([minimum, maximum]);
            return myColor(value);
    }
    
    // add the squares
        svg.selectAll()
            .data(data, function (d) { return d.Country + ':' + d.variable; })
            .enter()
            .append("rect")
            .attr("x", function (d) { return x(d.Country) })
            .attr("y", function (d) { return y(d.variable) })
            .attr("rx", 4)
            .attr("ry", 4)
            .attr("width", x.bandwidth())
            .attr("height", y.bandwidth())
    //Changed part
            .style("fill", function (d) { return colorPerVariable(minimum = d.min, maximum = d.max, value = d.value) })
    // 
            .style("stroke-width", 4)
            .style("stroke", "none")
            .style("opacity", 0.8)
            .on("mouseover", mouseover)
            .on("mousemove", mousemove)
            .on("mouseleave", mouseleave)
    }