# heatmap color and d3.js

This follows a recent post where I got my answer concerning possible web-based techno for plotting big heatmaps ($600 \times 600$ dissimilarity matrix).

Now, that I have achieved that, I'm struggling with setting the color scale. I would like some fine continuous color scale. For now I have plugged a discretization into 17 colors... not enough. With Python, pretty much is done with pyplot.pcolor.

How can I obtain such a 'continuous' color scale?

Here the difference between the two heatmaps parameterized by the same matrix:

Using matplotlib.pyplot in Python

Using D3.js and the code below

Here is the code:

<script src="http://d3js.org/d3.v3.js"></script>
<canvas id="heatmap"></canvas>
<script>
var tsvName = 'wasserstein_dists.tsv';
var canvas = document.getElementById('heatmap');
var ctx = canvas.getContext("2d");

var scale = 1;
var colors = ["#6363FF", "#6373FF", "#63A3FF", "#63E3FF", "#63FFFB", "#63FFCB",
"#63FF9B", "#63FF6B", "#7BFF63", "#BBFF63", "#DBFF63", "#FBFF63",
"#FFD363", "#FFB363", "#FF8363", "#FF7363", "#FF6364"];
var heatmapColor = d3.scale.linear()
.domain(d3.range(0, 1, 1.0 / (colors.length - 1)))
.range(colors);

// On charge le tsv :
d3.tsv(tsvName, function (d) {
return {
x: +d.x,
y: +d.y,
v: +d.v,
};
}, function (err, data) {
if (err != null) { return alert('No tsv file'); }

var size = Math.sqrt(data.length);
canvas.width = size * scale;
canvas.height = size * scale;

var c = d3.scale.linear()
.domain([d3.min(data, function (d) { return d.v; }), d3.max(data, function (d) { return d.v; })])
.range([0,1]);

data.forEach(function (d) {
ctx.fillStyle = heatmapColor(c(d.v));
ctx.fillRect(d.x * scale, d.y * scale, (d.x + 1) * scale, (d.y + 1) * scale);
});
});


Actually you are almost there. Just use the min/max function directly in the color scale instead of using the c var. Use the max/min function in the domain and the start/stop color in the range. The d3.scale is already a gradient function.

Something like:

<script src="http://d3js.org/d3.v3.js"></script>
<canvas id="heatmap"></canvas>
<script>
var tsvName = 'wasserstein_dists.tsv';
var canvas = document.getElementById('heatmap');
var ctx = canvas.getContext("2d");

var scale = 1;

// On charge le tsv :
d3.tsv(tsvName, function (d) {
return {
x: +d.x,
y: +d.y,
v: +d.v,
};
}, function (err, data) {
if (err != null) { return alert('No tsv file'); }

var size = Math.sqrt(data.length);
var heatmapColor = d3.scale.linear()
.domain([d3.min(data, function(d) { return d.v; }), d3.max(data, function(d) { return d.v; })])
.range(["#6363FF",  "#FF6364"]);
canvas.width = size * scale;
canvas.height = size * scale;

data.forEach(function (d) {
ctx.fillStyle = heatmapColor(d.v);
ctx.fillRect(d.x * scale, d.y * scale, (d.x + 1) * scale, (d.y + 1) * scale);
});
});


Of cause you have to first define data and then the color gradient with the min/max function.

• Thank you very much for the correction. It made me realized that the problem is not really the quantization of the color space, but which transform is used. I still obtain very much different results than matplotlib (I cannot see the blocks on the diagonal). So, I think I have to look for which transform matplotlib is doing on the input matrix...
– mic
Mar 2, 2016 at 14:28