Reputation: 355
I'm trying to draw a heatmap using D3. So far I was able to draw one by modifying the code from http://bl.ocks.org/tjdecke/5558084. At the moment, my legend is only showing two colors; yellow (for value 0) and red (for value 1). I would like to display the legend showing all the color gradient from yellow to red and the value associated with each color. Can someone help me with this? Part of the code is shown below. Thank you
// X-axis labels
// This has to be generated dynamically
loop_ids1 = ["HL_1S72_010", "HL_1S72_039", "HL_1S72_005", "HL_1VX6_037", "HL_2A64_002", "HL_2GDI_002", "HL_2GDI_004", "HL_2HOJ_002", "HL_2QBG_011", "HL_3DHS_002", "HL_3J7A_004", "HL_3U5F_006", "HL_3U5H_005", "HL_4A1B_005", "HL_4A1B_037", "HL_4BPP_006", "HL_4CUV_005", "HL_4CUX_006", "HL_4IOA_009", "HL_4QCN_009", "HL_4W21_039"];
// Y-axis labels
// This has to be generated dynamically
loop_ids2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21" ];
// Open and load the csv file
d3.csv("disc_parsed.csv", function(error, data) {
data.forEach(function(d) {
loop_id1 = d.loop_id1;
loop_id2 = d.loop_id2;
coordx = +d.coordx
coordy = +d.coordy
discrepancy = +d.discrepancy;
//console.log(d.discrepancy);
});
//var colorScale = d3.scale.quantile()
//.domain([0, buckets - 1, d3.max(data, function (d) { return d.discrepancy; })])
//.range(colors);
var colorScale = d3.scale.linear()
.domain([0,1])
.range(['yellow', 'red'])
// Set the svg container
var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Draw the x-axis label
var dayLabels = svg.selectAll(".dayLabel")
.data(loop_ids1)
.enter().append("text")
.text(function(d) {
return d;
})
.attr("x", 0)
.attr("y", function(d, i) {
return i * gridSize;
})
.style("text-anchor", "end")
.attr("transform", "translate(-5," + gridSize / 1.5 + ")")
.attr("class", function(d, i) { console.log(i);
return ((i >= 0)
? "dayLabel mono axis axis-workweek" : "dayLabel mono axis");
});
// Draw the y-axis label
var timeLabels = svg.selectAll(".timeLabel")
.data(loop_ids2)
.enter().append("text")
//.attr("font-size", 12)
//.attr("glyph-orientation-vertical: 180")
.text(function(d) {
return d;
})
.attr("x", function(d, i) {
return (i * gridSize);
})
.attr("y", 0)
.style("text-anchor", "middle")
.attr("transform", "translate(" + gridSize / 2 + '-5' + ")")
.attr("class", function(d, i) {
return ((i >= 0) ? "timeLabel mono axis axis-worktime" : "timeLabel mono axis");
});
// Create the paired elements
var heatMap = svg.selectAll(".coordy")
.data(data, function(d) { return d.coordx+':'+d.coordy;});
// Draw the grid to make the heatmap
heatMap.enter().append("rect")
.attr("x", function(d) { return d.coordy * gridSize; })
.attr("y", function(d) { return d.coordx * gridSize; })
.attr("rx", 4)
.attr("ry", 4)
.attr("class", "bordered")
.attr("width", gridSize)
.attr("height", gridSize)
.style("fill", function(d) {
return colorScale(d.discrepancy);
});
// Show the value of discrepancy between two motifs when the user hovers over a heatmap grid
heatMap.append("title").text(function(d) {
return d.loop_id1 + ':' + d.loop_id2 + ' = ' + d.discrepancy;
});
heatMap.exit().remove();
var legend = svg.selectAll(".legend")
.data(colorScale.domain())
legend.enter().append("g")
.attr("class", "legend");
// Draw the legend
legend.append("rect")
.attr("x", function(d, i) {
return legendElementWidth * i;
})
.attr("y", height)
.attr("width", legendElementWidth)
.attr("height", gridSize / 2)
.style("fill", function(d) {
return colorScale(d);
});
// Add text to the legend
legend.append("text")
.attr("class", "mono")
.text(function(d) {
return (d);
})
.attr("x", function(d, i) {
return legendElementWidth * i;
})
.attr("y", height + gridSize);
legend.exit().remove();
});
Upvotes: 1
Views: 1710
Reputation: 102174
The problem is the data
used for the legends:
var legend = svg.selectAll(".legend")
.data(colorScale.domain());
Right now, your data
is an array containing only 2 values, 0
and 1
, because of this snippet:
var colorScale = d3.scale.linear()
.domain([0,1])
What happened in the original code? In the original code, the author created an array with several values, using the quantiles()
function:
var legend = svg.selectAll(".legend")
.data([0].concat(colorScale.quantiles()), function(d) { return d; });
Solution:
You have several different solutions here, the easier and uglier one being simply hardcoding your data. So, if you want a legend with 6 rectangles:
var dataLegend = [0, 0.2, 0.4, 0.6, 0.8, 1];
var legend = svg.selectAll(".legend")
.data(dataLegend);
Upvotes: 2