2016-12-27 5 views
0

Ich habe eine Kalenderheatmap erstellt, aber das Problem ist, dass die Daten, die in die Bremse "über 4500" fallen, in schwarz statt der angegebenen Farbe #3d3768 markiert sind. Es sieht so aus, als ob die Farbe für diese Kategorie nicht gefunden werden kann. Warum?Kalender Heatmap: Farbe nicht zugewiesen

<!DOCTYPE html> 
<meta charset="utf-8"> 
<head> 
<title>Data Calendar</title> 
<style> 
    .month { 
     fill: none; 
     stroke: #000; 
     stroke-width: 2px; 
    } 
    .day { 
     fill: #fff; 
     stroke: #ccc; 
    } 
    text { 
     font-family:sans-serif; 
     font-size:1.5em; 
    } 
    .dayLabel { 
     fill:#aaa; 
     font-size:0.8em; 
    } 
    .monthLabel { 
     text-anchor:middle; 
     font-size:0.8em; 
     fill:#aaa; 
    } 
    .yearLabel { 
     fill:#aaa; 
     font-size:1.2em; 
    } 

    .key {font-size:0.5em;} 

</style> 
</head> 
<body> 
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script> 
<script> 

var breaks=[1500,2500,3500,4500,4550]; 
var colours=["#e2dff1","#b7b1dd","#8b82c8","#584f95","#3d3768"]; 

    //general layout information 
    var cellSize = 17; 
    var xOffset=20; 
    var yOffset=60; 
    var calY=50;//offset of calendar in each group 
    var calX=25; 
    var width = 960; 
    var height = 163; 
    var parseDate = d3.time.format("%d/%m/%y").parse; 
    format = d3.time.format("%d-%m-%Y"); 
    toolDate = d3.time.format("%d/%b/%y"); 

    d3.csv("data.csv", function(error, data) { 

     //set up an array of all the dates in the data which we need to work out the range of the data 
     var dates = new Array(); 
     var values = new Array(); 

     //parse the data 
     data.forEach(function(d) { 
       dates.push(parseDate(d.date)); 
       values.push(d.value); 
       d.date=parseDate(d.date); 
       d.value=d.value; 
       d.year=d.date.getFullYear();//extract the year from the data 
     }); 

     var yearlyData = d3.nest() 
      .key(function(d){return d.year;}) 
      .entries(data); 

     var svg = d3.select("body").append("svg") 
      .attr("width","90%") 
      .attr("viewBox","0 0 "+(xOffset+width)+" 540") 

     //title 
     svg.append("text") 
     .attr("x",xOffset) 
     .attr("y",20) 
     .text(title); 

     //create an SVG group for each year 
     var cals = svg.selectAll("g") 
      .data(yearlyData) 
      .enter() 
      .append("g") 
      .attr("id",function(d){ 
       return d.key; 
      }) 
      .attr("transform",function(d,i){ 
       return "translate(0,"+(yOffset+(i*(height+calY)))+")"; 
      }) 

     var labels = cals.append("text") 
      .attr("class","yearLabel") 
      .attr("x",xOffset) 
      .attr("y",15) 
      .text(function(d){return d.key}); 

     //create a daily rectangle for each year 
     var rects = cals.append("g") 
      .attr("id","alldays") 
      .selectAll(".day") 
      .data(function(d) { return d3.time.days(new Date(parseInt(d.key), 0, 1), new Date(parseInt(d.key) + 1, 0, 1)); }) 
      .enter().append("rect") 
      .attr("id",function(d) { 
       return "_"+format(d); 
       //return toolDate(d.date)+":\n"+d.value+" dead or missing"; 
      }) 
      .attr("class", "day") 
      .attr("width", cellSize) 
      .attr("height", cellSize) 
      .attr("x", function(d) { 
       return xOffset+calX+(d3.time.weekOfYear(d) * cellSize); 
      }) 
      .attr("y", function(d) { return calY+(d.getDay() * cellSize); }) 
      .datum(format); 

     //create day labels 
     var days = ['Su','Mo','Tu','We','Th','Fr','Sa']; 
     var dayLabels=cals.append("g").attr("id","dayLabels") 
     days.forEach(function(d,i) { 
      dayLabels.append("text") 
      .attr("class","dayLabel") 
      .attr("x",xOffset) 
      .attr("y",function(d) { return calY+(i * cellSize); }) 
      .attr("dy","0.9em") 
      .text(d); 
     }) 

     //let's draw the data on 
     var dataRects = cals.append("g") 
      .attr("id","dataDays") 
      .selectAll(".dataday") 
      .data(function(d){ 
       return d.values; 
      }) 
      .enter() 
      .append("rect") 
      .attr("id",function(d) { 
       return format(d.date)+":"+d.value; 
      }) 
      .attr("stroke","#ccc") 
      .attr("width",cellSize) 
      .attr("height",cellSize) 
      .attr("x", function(d){return xOffset+calX+(d3.time.weekOfYear(d.date) * cellSize);}) 
      .attr("y", function(d) { return calY+(d.date.getDay() * cellSize); }) 
      .attr("fill", function(d) { 
       if (d.value<breaks[0]) { 
        return colours[0]; 
       } 
       for (i=0;i<breaks.length+1;i++){ 
        if (d.value>=breaks[i]&&d.value<breaks[i+1]){ 
         return colours[i]; 
        } 
       } 
       if (d.value>breaks.length-1){ 
        return colours[breaks.length] 
       } 
      }) 

     //append a title element to give basic mouseover info 
     dataRects.append("title") 
      .text(function(d) { return toolDate(d.date)+":\n"+d.value+units; }); 

     //add montly outlines for calendar 
     cals.append("g") 
     .attr("id","monthOutlines") 
     .selectAll(".month") 
     .data(function(d) { 
      return d3.time.months(new Date(parseInt(d.key), 0, 1), 
            new Date(parseInt(d.key) + 1, 0, 1)); 
     }) 
     .enter().append("path") 
     .attr("class", "month") 
     .attr("transform","translate("+(xOffset+calX)+","+calY+")") 
     .attr("d", monthPath); 

     //retreive the bounding boxes of the outlines 
     var BB = new Array(); 
     var mp = document.getElementById("monthOutlines").childNodes; 
     for (var i=0;i<mp.length;i++){ 
      BB.push(mp[i].getBBox()); 
     } 

     var monthX = new Array(); 
     BB.forEach(function(d,i){ 
      boxCentre = d.width/2; 
      monthX.push(xOffset+calX+d.x+boxCentre); 
     }) 

     //create centred month labels around the bounding box of each month path 
     //create day labels 
     var months = ['JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC']; 
     var monthLabels=cals.append("g").attr("id","monthLabels") 
     months.forEach(function(d,i) { 
      monthLabels.append("text") 
      .attr("class","monthLabel") 
      .attr("x",monthX[i]) 
      .attr("y",calY/1.2) 
      .text(d); 
     }) 

     //create key 
     var key = svg.append("g") 
      .attr("id","key") 
      .attr("class","key") 
      .attr("transform",function(d){ 
       return "translate("+xOffset+","+(yOffset-(cellSize*1.5))+")"; 
      }); 

     key.selectAll("rect") 
      .data(colours) 
      .enter() 
      .append("rect") 
      .attr("width",cellSize) 
      .attr("height",cellSize) 
      .attr("x",function(d,i){ 
       return i*130; 
      }) 
      .attr("fill",function(d){ 
       return d; 
      }); 

     key.selectAll("text") 
      .data(colours) 
      .enter() 
      .append("text") 
      .attr("x",function(d,i){ 
       return cellSize+5+(i*130); 
      }) 
      .attr("y","1em") 
      .text(function(d,i){ 
       if (i<colours.length-1){ 
        return "up to "+breaks[i] + "%"; 
       } else { 
        return "over "+breaks[i-1] + "%"; 
       } 
      }); 

    });//end data load 

    //pure Bostock - compute and return monthly path data for any year 
    function monthPath(t0) { 
     var t1 = new Date(t0.getFullYear(), t0.getMonth() + 1, 0), 
      d0 = t0.getDay(), w0 = d3.time.weekOfYear(t0), 
      d1 = t1.getDay(), w1 = d3.time.weekOfYear(t1); 
     return "M" + (w0 + 1) * cellSize + "," + d0 * cellSize 
      + "H" + w0 * cellSize + "V" + 7 * cellSize 
      + "H" + w1 * cellSize + "V" + (d1 + 1) * cellSize 
      + "H" + (w1 + 1) * cellSize + "V" + 0 
      + "H" + (w0 + 1) * cellSize + "Z"; 
    } 

</script> 
</body> 
</html> 
+0

Warum iterieren Sie 'breaks.length + 1 '? – epascarello

+0

@epascarello: Danke, dass du es bemerkt hast. Ich wechselte zu "i = 0; i Dinosaurius

Antwort

0

Ihr Farbauswahlcode könnte etwas verkleinert werden, und die Verwendung einer d3-Skala zur Auswahl Ihrer Farbe würde dies ebenfalls viel sauberer machen. Aber letztlich liegt Ihr Problem hier:

  if (d.value>breaks.length-1){ 
       return colours[breaks.length] 
      } 

Dieser Abschnitt des Codes wird nur aufgerufen, wenn eine Farbe noch nicht zurückgegeben worden ist, das heißt, für diese Werte, die größer sind als 4550. Während ich bin nicht sicher, warum Wenn die If-Anweisung in diesem Codeblock benötigt wird, haben Ihre Arrays breaks und colours die gleiche Länge. Im Wesentlichen geben Sie array[array.length] zurück, die keinen Wert zurückgeben, da Arrays null indiziert sind. Sie möchten wahrscheinlich colours[colours.length-1] zurückgeben, wie Sie die letzte angegebene Farbe möchten.


Edit: Auch, wenn Sie eine Farbe für die unten Ihre niedrigsten Pause zuweisen (was es scheint, Sie tun) und die oben Ihren höchsten, werden Sie eine brauchen mehr Farbe als Bruchwert. ZB: Eine Ein-Bruch-Skala hat zwei Farben für diejenigen oberhalb/unterhalb der Pause. Sie können jedoch absichtlich colours[0] auf beide angewendet haben: Werte unter breaks[0] und Werte zwischen breaks[0] und breaks[1]:

  if (d.value<breaks[0]) { 
       return colours[0]; 
      } 
      for (i=0;i<breaks.length+1;i++){ 
       if (d.value>=breaks[i]&&d.value<breaks[i+1]){ 
        return colours[i]; 
       } 
      } 
Verwandte Themen