How can I set the background color of a svg element which contains a D3 heat map?

1.1k views Asked by At

I am building a heat map which displays the tweeting activity of an account during the week. My dataset is made of an array of dictonaries containing the weekday, the hour and the count of how many times the weekday+hour combination repeats. Since usually people stop tweeting during the night, there are some weekday+hour combinations which do not exist in the dataset. My problem is that when I draw the rectangles, I can only draw them for the existing combinations, and the non-existing ones remain blank. This is a link to the result, hopefully it'll make things clearer:

enter image description here

As you can see, there are blank spaces between 2:00 and 8:00 am.

I have no idea how to solve this problem, but I thought I could give a white background to the whole heat map before coloring the rectangles containing the existing combinations, so that the non-existing ones become white instead of being blank. How can i do this? If this is not possible, is there another solution to my problem?

This is my code:

[var data = timestamps_final;

var days = \["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"\], times = \["00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"\];

var margin = { top: 40, right: 50, bottom: 40, left: 50 };

var w = Math.max(Math.min(window.innerWidth, 1000), 500) - margin.left - margin.right - 20,ngridSize = Math.floor(w / times.length), h = gridSize * (days.length + 2);

var svg = d3.select("#heat_map")
        .append("svg")
        .attr("width", w + margin.top + margin.bottom)
        .attr("height", h + margin.left + margin.right)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var colours = d3.scaleLinear()
        .range(\["#F0C881", "#F244C7", "#173490",\])
        .domain(\[1, 50, 100\]);

var dayLabels = svg.selectAll(".dayLabel")
        .data(days)
        .enter()
        .append("text")
        .text(function (d) { return d; })
        .attr("x", 0)
        .attr("y", function (d, i) { return i * gridSize; })
        .style("text-anchor", "end")
        .style('fill', 'white')
        .attr("transform", "translate(-6," + gridSize / 1.5 + ")")

var timeLabels = svg.selectAll(".timeLabel")
        .data(times)
        .enter()
        .append("text")
        .text(function (d) { return d; })
        .attr("x", function (d, i) { return i * gridSize; })
        .attr("y", 0)
        .style("text-anchor", "middle")
        .style('fill', 'white')
        .attr("transform", "translate(" + gridSize / 2 + ", -6)");

var rectangles = svg.selectAll("rect")
        .data(data)
        .enter()
        .append("rect")
        .attr("x", function (d) { return d.hour * 36; })
        .attr("y", function (d) { return d.weekday * 36; })
        .attr("width", 36)
        .attr("height", 36)
        .style("stroke-width", 1)
        .style("stroke", "white")
        .style("fill", function (d) { return colours(d.value); });

Thank you for your help.

1

There are 1 answers

4
rioV8 On

Add a big white rect before you add the week+hour rects

svg.append("rect")
    .style("fill", "white")
    .attr("width", 36 * 24)
    .attr("height", 36 * 7);

var rectangles = svg.selectAll("rect")
        .data(data)
        .enter()
        .append("rect")
        .attr("x", function (d) { return d.hour * 36; })
        .attr("y", function (d) { return d.weekday * 36; })
        .attr("width", 36)
        .attr("height", 36)
        .style("stroke-width", 1)
        .style("stroke", "white")
        .style("fill", function (d) { return colours(d.value); });