简体   繁体   中英

How to update text in heatmap using D3?

I've created a D3 heatmap based on this example , and have written an update function for it. Here's the relevant code for the base heatmap:

<!DOCTYPE html>
<html lange = "en">
<head>
    <meta charset="UTF-8">
    <title>Heatmap</title>
    <script type ="text/javascript" src="d3/d3.v3.js"></script>
    <script type ="text/javascript" src="updateHeatmap.js"> </script>
    <style type ="text/css">  

    .btn { 
        display: inline; 
    }


        rect.bordered {
        stroke: #E6E6E6;
        stroke-width:2px;   
      }

      text.mono {
        font-size: 9pt;
        font-family: Consolas, courier;
        fill: #aaa;
      }

      text.axis-workweek {
        fill: #000;
      }

      text.axis-worktime {
        fill: #000;
      }</style>
</head>


<body>

    <div id="n1" class="btn">
        <input name="updateButton" 
               type="button" 
               value="1" 
        />
    </div>
    <div id="n2" class="btn">
        <input name="updateButton" 
               type="button" 
               value="2" 
        />
    </div>



    <div id="chart"></div>
    <script type="text/javascript">
    var margin = {top:50, right:0, bottom:100, left:30},
        width=960-margin.left-margin.right,
        height=430-margin.top-margin.bottom,
        gridSize=Math.floor(width/24),
        legendElementWidth=gridSize*2.665,
        buckets = 10,
        colors = ["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],
        days = ["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
    times = ["12am", "1am", "2am", "3am", "4am", "5am", "6am", "7am", "8am", "9am", "10am", "11am", "12am", "1pm", "2pm", "3pm", "4pm", "5pm", "6pm", "7pm", "8pm", "9pm", "10pm", "11pm"];

    var heatmap;
    var legend;

    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+")");

    d3.csv("1.csv", function(d){
        return {
            day:+d.day2,
            hour:+d.hour,
            value:+d.per_day_per_hour
            };
        },
        function(error, data){

            console.log(data);

            var colorScale = d3.scale.quantile()
                .domain([0, (d3.max(data, function(d){return d.value;})/2), d3.max(data, function(d){return d.value;})])
                .range(colors);


            var dayLabels = svg.selectAll(".dayLabel")
                .data(days)
                .enter().append("text")
                .text(function (d) {return d; })
                .attr("y", function (d, i){ return i*gridSize;})
                .style("text-anchor", "end")
                .attr("transform", "translate(-6," + gridSize/1.5+")")
                .attr("class", function(d, i) { return ((i>=0 && i<=4) ? "dayLabel mono axis axis-workweek": "dayLabel mono axis"); });

            var timeLabels = svg.selectAll(".timeLabel")
                .data(times)
                .enter().append("text")
                .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+", -6)")
                .attr("class", function(d, i) { return ((i>=9 && i<= 17) ? "timeLabel mono axis axis-worktime": "timeLabel mono axis"); });

            var heatMap = svg.selectAll(".hour")
                .data(data)
                .enter().append("rect")
                .attr("x", function(d) {return (d.hour) * gridSize;})
                .attr("y", function(d) {return (d.day) * gridSize;})
                .attr("rx", 4)
                .attr("ry", 4)
                .attr("class", "hour bordered")
                .attr("width", gridSize)
                .attr("height", gridSize)
                .style("fill", colors[0]);

            heatMap.transition().duration(1000)
                .style("fill", function(d){ return colorScale(d.value);});

            heatMap.append("title").text(function(d) {return d.value;});

            var legend = svg.selectAll(".legend")
                .data([0].concat(colorScale.quantiles()), function(d) {return d;})
                .enter().append("g")
                .attr("class", "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, i) {return colors[i]; });

            legend.append("text")
                .attr("class", "mono")
                .text(function(d) {return "≥ "+d.toString().substr(0,4);})
                .attr("x", function(d, i){ return legendElementWidth *i;})
                .attr("y", height+ gridSize);



            d3.select("#n1")
                .on("click", function() {
                    updateHeatmap("1_1.csv");
                });


            d3.select("#n2")
                .on("click", function() {
                    updateHeatmap("1_2.csv");
                });     

        ;       
        }
);
</script>

<script>

</script>

</body>
</html>

The code above is essentially the same as that in the fiddle I've linked to up top, except that it includes 2 buttons, and has the legend, svg, and heatmap variables declared globally.

Here's the meat of my question, which has to do with the update function I created to load in two new CSVs:

function updateHeatmap(x){
    svg.selectAll(".legend").attr("opacity", 0);
    d3.csv(x, function(d){
        return {
            day:+d.day2,
            hour:+d.hour,
            value:+d.per_day_per_hour
            };
        },

        function(error, data){


        colorScale = d3.scale.quantile()
            .domain([0, (d3.max(data, function(d){return d.value;})/2), d3.max(data, function(d){return d.value;})])
            .range(colors);


        var heatMap = svg.selectAll(".hour")
            .data(data)
            .transition().duration(1000)
            .style("fill", function(d){ return colorScale(d.value);});

        heatMap.selectAll("title").text(function(d) {return d.value;});

        var legend = svg.selectAll(".legend")
            .data([0].concat(colorScale.quantiles()), function(d) {return d;})
            .enter().append("g")
            .attr("class", "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, i) {return colors[i]; });

        legend.append("text")
            .attr("class", "mono")
            .text(function(d) {return "≥ "+d.toString().substr(0,4);})
            .attr("x", function(d, i){ return legendElementWidth *i;})
            .attr("y", height+ gridSize);



        }
    )
}

I've managed to update the color of the heatmap squares (huzzah), but can't get the legend that sits below the heatmap to cooperate, and can't get the values underlying each square to display on hover like I did on initial loading. I get a feeling that it's because my JS is pretty flaky (as is, let's face it, my D3), but can't be sure — I think it may have to do with my screwing up the appropriate syntax for selecting the text element (ie, I'm unsure of how to do it the right way).

To sum up : legend in this heatmap (here's the gist block) isn't updating properly, and the on-hover values for each of the squares don't appear on update. Yikes. Any suggestions?

I've updated my example to allow switching between datasets - this should help.

http://bl.ocks.org/tjdecke/5558084

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM