Alberto
Alberto

Reputation: 467

D3 heatmap color range updating with slider

I am using D3 and the JQuery Slider to produce an heatmap whose colors are automatically refreshed when I change the position of the cursor of the slider (which represents the color scale range). Although it works fine when i first click on the slider, it doesn't seem to refresh afterwards. I post the source in case you would like to point out my mistake:

<HEAD>
<TITLE>Heatmap</TITLE>
</HEAD>
<BODY BGCOLOR="WHITE">

<CENTER>
<H1>Heatmap</H1>

<H5>Heatmap should instantly display bidimensional data (adjustable thresholds)</H5>




<script src="http://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<link rel="stylesheet" href="/resources/demos/style.css" />

<div id="slider"></div>
<p>
 <div id="heatmap"></div>

<script>

var minval= 0;
var maxval= 1000;


$( "#slider" ).slider({
    range: true,
    min: 0,
    max: 1000,
    values: [0, 1000],
    slide: function( event, ui ) {
      var minval = ui.values[0];
      var maxval = ui.values[1];
      console.log("begin:", minval, "end:", maxval);
      draw(minval, maxval); 
    }
});


var margin = {top: 0, right: 20, bottom: 20, left: 20},
    width = 300 - margin.left - margin.right,
    height = 300 - margin.top - margin.bottom;

var svg = d3.select("#heatmap").append("svg:svg");

var data = [[1000,500,1],[500,1,1000],[1000,54,800]];

var x = d3.scale.linear()
    .range([0, width])
    .domain([0,data[0].length]);

var y = d3.scale.linear()
    .range([0, height])
    .domain([0,data.length]);

svg.attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom)
        .append("g")
        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var colorLow = 'white', colorMed = 'green', colorHigh = 'red';


function draw(minval,maxval){

    var colorScale = d3.scale.linear()
         .domain([minval, maxval])
         .range([colorLow, colorHigh]);

    var row = svg.selectAll(".row")
            .data(data)
            .enter().append("svg:g")
            .attr("class", "row");

    var col = row.selectAll(".cell")
               .data(function (d,i) { return d.map(function(a) { return {value: a, row: i}; } ) })
               .enter().append("svg:rect")
                 .attr("class", "cell")
                 .attr("x", function(d, i) { return x(i); })
                 .attr("y", function(d, i) { return y(d.row); })
                 .attr("width", x(1))
                 .attr("height", y(1))
                 .style("fill", function(d) { return colorScale(d.value); });

}



</script>
</head>
<body>

</CENTER>
</body>

Upvotes: 1

Views: 2997

Answers (1)

Lars Kotthoff
Lars Kotthoff

Reputation: 109232

It doesn't work the second time because you are operating on the .enter() selection, which will be empty the second time draw() is called because the elements exist already.

To fix this, move the declaration of row and col outside the draw() function. Inside the draw() function, only keep the code that actually changes. Something like

function draw(minval,maxval){
    var colorScale = d3.scale.linear()
         .domain([minval, maxval])
         .range([colorLow, colorHigh]);
    col.style("fill", function(d) { return colorScale(d.value); });
}

Upvotes: 3

Related Questions