jrowen / rhandsontable

A htmlwidgets implementation of Handsontable.js
http://jrowen.github.io/rhandsontable/
Other
383 stars 148 forks source link

`renderer_heatmap` should use `parseFloat` instead of `parseInt` #378

Open pnacht opened 3 years ago

pnacht commented 3 years ago

The default heatmap renderer is

function (instance, td, row, col, prop, value, cellProperties) {
  Handsontable.renderers.TextRenderer.apply(this, arguments);
  heatmapScale  = chroma.scale(['#ED6D47', '#17F556']);

  if (instance.heatmap[col]) {
    mn = instance.heatmap[col].min;
    mx = instance.heatmap[col].max;

    pt = (parseInt(value, 10) - mn) / (mx - mn);    // here's the problem

    td.style.backgroundColor = heatmapScale(pt).hex();
  }
}

Pretty straightforward: if the column is a heatmap, get the minimum and maximum values of the column, get the value of the cell and then interpolate the background color.

However, the cell's value is converted away from a string using parseInt(value, 10), which collapses the value to an integer, losing any decimal information. This therefore means that (not so) similar values are collapsed into the same color.

For example, see the output from the example given for hot_heatmap:

set.seed(42)
MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
                                                   letters[1:5]))

rhandsontable(MAT) %>%
    hot_heatmap()

image

Note how each column has only three or four colors, since all numbers are truncated to either +/-2, +/-1, or 0.

This can be fixed by simply replacing parseInt() with parseFloat():

set.seed(42)
MAT = matrix(rnorm(50), nrow = 10, dimnames = list(LETTERS[1:10],
                                                   letters[1:5]))

rhandsontable(MAT) %>%
    hot_heatmap(renderer = "
        function (instance, td, row, col, prop, value, cellProperties) {
          Handsontable.renderers.TextRenderer.apply(this, arguments);
          heatmapScale  = chroma.scale(['#ED6D47', '#17F556']);

          if (instance.heatmap[col]) {
            mn = instance.heatmap[col].min;
            mx = instance.heatmap[col].max;

            pt = (parseFloat(value) - mn) / (mx - mn);    // changed to parseFloat!

            td.style.backgroundColor = heatmapScale(pt).hex();
          }
        }")

image