1
$\begingroup$

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 matplotlib.pyplot in python

Using D3.js and the code below 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);
  });
});

$\endgroup$

1 Answer 1

2
$\begingroup$

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.

$\endgroup$
1
  • $\begingroup$ 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... $\endgroup$
    – mic
    Mar 2, 2016 at 14:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.