javascript - D3 备用日历 - 按 Bin 着色

标签 javascript d3.js

我们看到的备用 D3 日历 here使用打开和关闭列的值来计算日历的颜色。我正在尝试修改代码以根据“打开”列的阈值/分级为日历着色。下面修改后的代码将 csv 文件分成 10 个桶。我被卡住了,因为我的代码不起作用(日历没有颜色,工具提示显示“2008-01-01:未定义”)。任何帮助,将不胜感激。

var width = 960,
        height = 750,
        cellSize = 25; // cell size

    var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
    var shift_up = cellSize * 3;

    var day = d3.time.format("%w"), // day of the week
        day_of_month = d3.time.format("%e"),// day of the month
        day_of_year = d3.time.format("%j"),
        week = d3.time.format("%U"), // week number of the year
        month = d3.time.format("%m"), // month number
        year = d3.time.format("%Y"),
        percent = d3.format(".1%"),
        format = d3.time.format("%Y-%m-%d");

    var color = d3.scale.quantize()
    .domain([1,10])
   // .range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));
   .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598","#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F"]);

    var svg = d3.select("#chart").selectAll("svg")
        .data(d3.range(2008, 2011))
      .enter().append("svg")
        .attr("width", width)
        .attr("height", height)
        .attr("class", "RdYlGn")
      .append("g");

    var rect = svg.selectAll(".day")
        .data(function(d) { 
          return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
        })
      .enter().append("rect")
        .attr("class", "day")
        .attr("width", cellSize)
        .attr("height", cellSize)
        .attr("x", function(d) {
          var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
          return day(d) * cellSize + month_padding; 
        })
        .attr("y", function(d) { 
          var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
          var row_level = Math.ceil(month(d) / (no_months_in_a_row));
          return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
        })
        .datum(format);

    var month_titles = svg.selectAll(".month-title")  // Jan, Feb, Mar and the whatnot
          .data(function(d) { 
            return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
        .enter().append("text")
          .text(monthTitle)
          .attr("x", function(d, i) {
            var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
            return month_padding;
          })
          .attr("y", function(d, i) {
            var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
            var row_level = Math.ceil(month(d) / (no_months_in_a_row));
            return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
          })
          .attr("class", "month-title")
          .attr("d", monthTitle);

    var year_titles = svg.selectAll(".year-title")  // Jan, Feb, Mar and the whatnot
          .data(function(d) { 
            return d3.time.years(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
        .enter().append("text")
          .text(yearTitle)
          .attr("x", function(d, i) { return width/2 - 100; })
          .attr("y", function(d, i) { return cellSize*5.5 - shift_up; })
          .attr("class", "year-title")
          .attr("d", yearTitle);


    //  Tooltip Object
    var tooltip = d3.select("body")
      .append("div").attr("id", "tooltip")
      .style("position", "absolute")
      .style("z-index", "10")
      .style("visibility", "hidden")
      .text("a simple tooltip");

    d3.csv("https://raw.githubusercontent.com/devsar/d3talk/master/dji.csv", function(error, csv) {
    
    /*--- start of my code --- */
    var mvalues=[];
    //reading all the metric values into an array
    for (i=0;i<csv.length;i++){
      mvalues.push(Number(csv[i].Open));
    }
     var histGenerator=d3.layout.histogram()
                .range([d3.min(mvalues),d3.max(mvalues)])
                .bins(10);


    var bins = histGenerator(mvalues);

      //Assigning a value to the group column(created in this loop only) determining which bucket the row falls for example : Row 1 Metric Value may fall in bucket 6
      for (j=0;j<bins.length;j++)
        {

          for  (i=0;i<csv.length;i++)
            {
          if(((Number(csv[i].Open)> bins[j].x) && (Number(csv[i].Open)<=bins[j].x+bins[j].dx)))
            {
              csv[i].Group = j;

            }

            }
        }
        
       
        var data = d3.nest()
        .key(function(d) { return d.Date; })
        .rollup(function(d) { return d[0].Group; })
        .map(csv);
        // debugger;        

        
     /*--- end of my code --- */ 
  
  
        /*var data = d3.nest()
        .key(function(d) { return d.Date; })
        .rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
        .map(csv);
    */
      rect.filter(function(d) { return d in data; })
          .attr("class", function(d) { return "day " + color(data[d]); })
        .select("title")
          .text(function(d) { return d + ": " + data[d]; });

      //  Tooltip
      rect.on("mouseover", mouseover);
      rect.on("mouseout", mouseout);
      function mouseover(d) {
        tooltip.style("visibility", "visible");
      //  var percent_data = (data[d] !== undefined) ? percent(data[d]) : percent(0);
           var percent_data = (data[d] !== undefined) ? data[d] : 0;  //modified above line of code to display only Open value
      
        var purchase_text = d + ": " + percent_data;

        tooltip.transition()        
                    .duration(200)      
                    .style("opacity", .9);      
        tooltip.html(purchase_text)  
                    .style("left", (d3.event.pageX)+30 + "px")     
                    .style("top", (d3.event.pageY) + "px"); 
      }
      function mouseout (d) {
        tooltip.transition()        
                .duration(500)      
                .style("opacity", 0); 
        var $tooltip = $("#tooltip");
        $tooltip.empty();
      }

    });

    function dayTitle (t0) {
      return t0.toString().split(" ")[2];
    }
    function monthTitle (t0) {
      return t0.toLocaleString("en-us", { month: "long" });
    }
    function yearTitle (t0) {
      return t0.toString().split(" ")[3];
    }
body {
        font: 1.1em sans-serif;
      }

      #chart{
        width: 800px;
        margin: 0 auto;
      }
      .background {
        fill: #eee;
      }

      line {
        stroke: #fff;
      }

      text.active {
        fill: red;
      }

      .day {
        fill: #fff;
        stroke: #ccc;
      }

      .month {
        fill: none;
        stroke: #fff;
        stroke-width: 4px;
      }
      .year-title {
        font-size: 1.5em;
      }

      /* color ranges */
      .RdYlGn .q0-11{fill:rgb(165,0,38)}
      .RdYlGn .q1-11{fill:rgb(215,48,39)}
      .RdYlGn .q2-11{fill:rgb(244,109,67)}
      .RdYlGn .q3-11{fill:rgb(253,174,97)}
      .RdYlGn .q4-11{fill:rgb(254,224,139)}
      .RdYlGn .q5-11{fill:rgb(255,255,191)}
      .RdYlGn .q6-11{fill:rgb(217,239,139)}
      .RdYlGn .q7-11{fill:rgb(166,217,106)}
      .RdYlGn .q8-11{fill:rgb(102,189,99)}
      .RdYlGn .q9-11{fill:rgb(26,152,80)}
      .RdYlGn .q10-11{fill:rgb(0,104,55)}

      /* hover info */
      #tooltip {
        background-color: #fff;
        border: 2px solid #ccc;
        padding: 10px;
      }
<script src="http://d3js.org/d3.v3.js"></script>

最佳答案

解决方法:

  • 不要将 d3.min()d3.max() 用于数字最小最大值,请阅读文档
  • 设置一个等于 bin 编号的类并使用 CSS 样式进行着色,因为已经有用于未着色矩形的 CSS 样式
  • 不要将颜色十六进制用作 CSS 类

您必须自己修复工具提示,因为它使用 jQuery 而示例中未包含它。

将图表的 div 放在 html 中。

var width = 960,
        height = 750,
        cellSize = 25; // cell size

    var no_months_in_a_row = Math.floor(width / (cellSize * 7 + 50));
    var shift_up = cellSize * 3;

    var day = d3.time.format("%w"), // day of the week
        day_of_month = d3.time.format("%e"),// day of the month
        day_of_year = d3.time.format("%j"),
        week = d3.time.format("%U"), // week number of the year
        month = d3.time.format("%m"), // month number
        year = d3.time.format("%Y"),
        percent = d3.format(".1%"),
        format = d3.time.format("%Y-%m-%d");

    var color = d3.scale.quantize()
    .domain([1,10])
   // .range(d3.range(11).map(function(d) { return "q" + d + "-11"; }));
   .range(["#5E4FA2", "#3288BD", "#66C2A5", "#ABDDA4", "#E6F598","#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43", "#D53E4F"]);

    var svg = d3.select("#chart").selectAll("svg")
        .data(d3.range(2008, 2011))
      .enter().append("svg")
        .attr("width", width)
        .attr("height", height)
        .attr("class", "RdYlGn")
      .append("g");

    var rect = svg.selectAll(".day")
        .data(function(d) { 
          return d3.time.days(new Date(d, 0, 1), new Date(d + 1, 0, 1));
        })
      .enter().append("rect")
        .attr("class", "day")
        .attr("width", cellSize)
        .attr("height", cellSize)
        .attr("x", function(d) {
          var month_padding = 1.2 * cellSize*7 * ((month(d)-1) % (no_months_in_a_row));
          return day(d) * cellSize + month_padding; 
        })
        .attr("y", function(d) { 
          var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
          var row_level = Math.ceil(month(d) / (no_months_in_a_row));
          return (week_diff*cellSize) + row_level*cellSize*8 - cellSize/2 - shift_up;
        })
        .datum(format);

    var month_titles = svg.selectAll(".month-title")  // Jan, Feb, Mar and the whatnot
          .data(function(d) { 
            return d3.time.months(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
        .enter().append("text")
          .text(monthTitle)
          .attr("x", function(d, i) {
            var month_padding = 1.2 * cellSize*7* ((month(d)-1) % (no_months_in_a_row));
            return month_padding;
          })
          .attr("y", function(d, i) {
            var week_diff = week(d) - week(new Date(year(d), month(d)-1, 1) );
            var row_level = Math.ceil(month(d) / (no_months_in_a_row));
            return (week_diff*cellSize) + row_level*cellSize*8 - cellSize - shift_up;
          })
          .attr("class", "month-title")
          .attr("d", monthTitle);

    var year_titles = svg.selectAll(".year-title")  // Jan, Feb, Mar and the whatnot
          .data(function(d) { 
            return d3.time.years(new Date(d, 0, 1), new Date(d + 1, 0, 1)); })
        .enter().append("text")
          .text(yearTitle)
          .attr("x", function(d, i) { return width/2 - 100; })
          .attr("y", function(d, i) { return cellSize*5.5 - shift_up; })
          .attr("class", "year-title")
          .attr("d", yearTitle);


    //  Tooltip Object
    var tooltip = d3.select("body")
      .append("div").attr("id", "tooltip")
      .style("position", "absolute")
      .style("z-index", "10")
      .style("visibility", "hidden")
      .text("a simple tooltip");

    d3.csv("https://raw.githubusercontent.com/devsar/d3talk/master/dji.csv", function(error, csv) {
    
    /*--- start of my code --- */
    var mvalues=[];
    //reading all the metric values into an array
    for (i=0;i<csv.length;i++){
      csv[i].Open = Number(csv[i].Open);
      mvalues.push(csv[i].Open);
    }
     var histGenerator=d3.layout.histogram()
                .range([d3.min(mvalues), d3.max(mvalues)])
                .bins(10);


    var bins = histGenerator(mvalues);

      //Assigning a value to the group column(created in this loop only) determining which bucket the row falls for example : Row 1 Metric Value may fall in bucket 6
      for (j=0;j<bins.length;j++)
        {

          for  (i=0;i<csv.length;i++)
            {
          if(((csv[i].Open> bins[j].x) && (csv[i].Open<=bins[j].x+bins[j].dx)))
            {
              csv[i].Group = j;

            }

            }
        }
        
        
        var data = d3.nest()
        .key(function(d) { return d.Date; })
        .rollup(function(d) { return d[0].Group; })
        .map(csv);
        
     /*--- end of my code --- */ 
  
  
        /*var data = d3.nest()
        .key(function(d) { return d.Date; })
        .rollup(function(d) { return (d[0].Close - d[0].Open) / d[0].Open; })
        .map(csv);
    */
      rect.filter(function(d) { return d in data; })
          .attr("class", function(d) { return `day q${data[d]}-11`; })
          //.attr("fill", function(d) { return color(data[d]); })
        .select("title")
          .text(function(d) { return d + ": " + data[d]; });

      //  Tooltip
      //rect.on("mouseover", mouseover);
      //rect.on("mouseout", mouseout);
      function mouseover(d) {
        tooltip.style("visibility", "visible");
      //  var percent_data = (data[d] !== undefined) ? percent(data[d]) : percent(0);
           var percent_data = (data[d] !== undefined) ? data[d] : 0;  //modified above line of code to display only Open value
      
        var purchase_text = d + ": " + percent_data;

        tooltip.transition()        
                    .duration(200)      
                    .style("opacity", .9);      
        tooltip.html(purchase_text)  
                    .style("left", (d3.event.pageX)+30 + "px")     
                    .style("top", (d3.event.pageY) + "px"); 
      }
      function mouseout (d) {
        tooltip.transition()        
                .duration(500)      
                .style("opacity", 0); 
        var $tooltip = document.getElementById("tooltip");
        $tooltip.empty();
      }

    });

    function dayTitle (t0) {
      return t0.toString().split(" ")[2];
    }
    function monthTitle (t0) {
      return t0.toLocaleString("en-us", { month: "long" });
    }
    function yearTitle (t0) {
      return t0.toString().split(" ")[3];
    }
body {
        font: 1.1em sans-serif;
      }

      #chart{
        width: 800px;
        margin: 0 auto;
      }
      .background {
        fill: #eee;
      }

      line {
        stroke: #fff;
      }

      text.active {
        fill: red;
      }

      .day {
        fill: #fff;
        stroke: #ccc;
      }

      .month {
        fill: none;
        stroke: #fff;
        stroke-width: 4px;
      }
      .year-title {
        font-size: 1.5em;
      }

      /* color ranges */
      .RdYlGn .q0-11{fill:rgb(165,0,38)}
      .RdYlGn .q1-11{fill:rgb(215,48,39)}
      .RdYlGn .q2-11{fill:rgb(244,109,67)}
      .RdYlGn .q3-11{fill:rgb(253,174,97)}
      .RdYlGn .q4-11{fill:rgb(254,224,139)}
      .RdYlGn .q5-11{fill:rgb(255,255,191)}
      .RdYlGn .q6-11{fill:rgb(217,239,139)}
      .RdYlGn .q7-11{fill:rgb(166,217,106)}
      .RdYlGn .q8-11{fill:rgb(102,189,99)}
      .RdYlGn .q9-11{fill:rgb(26,152,80)}
      .RdYlGn .q10-11{fill:rgb(0,104,55)}

      /* hover info */
      #tooltip {
        background-color: #fff;
        border: 2px solid #ccc;
        padding: 10px;
      }
<script src="http://d3js.org/d3.v3.js"></script>
<div id="chart"></div>

编辑

现在您已将 Open 列转换为 Number,然后是 d3.min()d3.max() 给出正确的结果。我相应地修改了示例。

关于javascript - D3 备用日历 - 按 Bin 着色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51714675/

相关文章:

javascript - 检查参数

javascript - 在谷歌脚本中循环

d3.js - C3 图表显示负 y 标签

javascript - 将 d3force 应用于具有多个组的网络

javascript - 优化 JavaScript 动画

json - d3.js svg 从 (geo/topo)json 绘制轮廓线

javascript - 滚动 Div 部分的动画计数器?

javascript - react-native-router-flux 具有替换、重置和刷新功能的刷新组件

javascript - 如何在文本字段中使用空气泡不消失的条件

javascript - d3画笔并设置带有时间刻度的最小刻度线