D3.js:如何在版本4中向直方图添加分配线

时间:2016-12-19 13:51:59

标签: javascript html d3.js

注意:This question曲线有关。

这是我目前的状态: enter image description here

我不太明白如何为直方图绘制两个分布 line ,你会看到我的尝试在代码中被注释掉了。我的主要问题是如何给出x和y参数,因为每个观察结果只附加一个值。

这是我的代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
    .bar1 rect {
      fill: rgba(0,0,255,0.6);
    }

    .bar1:hover rect{
      fill: rgba(0,0,255,0.9);
    }

    .bar1 text {
      fill: #fff;
      font: 10px sans-serif;
    }

    .bar2 rect {
      fill: rgba(255,0,0,0.6);
    }

    .bar2:hover rect{
      fill: rgba(255,0,0,0.9);
    }

    .bar2 text {
      fill: #fff;
      font: 10px sans-serif;
    }

    </style>
    <script src="https://d3js.org/d3.v4.min.js"></script>

    <script>

    function draw(data) {

      var allCongruentData = data.map(function(e){ return e.Congruent;});
      var allIncongruentData = data.map(function(e){ return e.Incongruent;});

      var formatCount = d3.format(",.0f");

      var svg = d3.select("svg"),
          margin = {top: 10, right: 30, bottom: 30, left: 30},
          width = +svg.attr("width") - margin.left - margin.right,
          height = +svg.attr("height") - margin.top - margin.bottom,
          g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      var x = d3.scaleLinear()
          .rangeRound([0, width])
          .domain([8, 36]);

      var bins1 = d3.histogram()
          .domain(x.domain())
          .thresholds(x.ticks(40))
          (allCongruentData);

      // var line = d3.line()
      //       .x(function(d) { return ???; })
      //       .y(function(d) { return y(d.Congruent); })
      //       .curve(d3.curveCatmullRom.alpha(0.5));

      var bins2 = d3.histogram()
          .domain(x.domain())
          .thresholds(x.ticks(40))
          (allIncongruentData);

      var y = d3.scaleLinear()
          .domain([0, d3.max(bins1, function(d) { return d.length; })])
          .range([height, 0]);

      var bar1 = g.selectAll(".bar1")
        .data(bins1)
        .enter().append("g")
          .attr("class", "bar1")
          .attr("transform", function(d) { return "translate(" + x(d.x0) + "," + y(d.length) + ")"; });

      bar1.append("rect")
          .attr("x", 0.5)
          .attr("width", x(bins1[0].x1) - x(bins1[0].x0) - 1)
          .attr("height", function(d) { return height - y(d.length); });


      var bar2 = g.selectAll(".bar2")
        .data(bins2)
        .enter().append("g")
          .attr("class", "bar2")
          .attr("transform", function(d) { return "translate(" + x(d.x0) + "," + y(d.length) + ")"; });

      bar2.append("rect")
          .attr("x", 0.5)
          .attr("width", x(bins2[0].x1) - x(bins2[0].x0) - 1)
          .attr("height", function(d) { return height - y(d.length); });

      bar1.append("text")
          .attr("dy", ".75em") // why?
          .attr("y", 6)
          .attr("x", (x(bins1[0].x1) - x(bins1[0].x0)) / 2)
          .attr("text-anchor", "middle")
          .text(function(d) { return formatCount(d.length); });

      bar2.append("text")
          .attr("dy", ".75em") // why?
          .attr("y", 6)
          .attr("x", (x(bins2[0].x1) - x(bins2[0].x0)) / 2)
          .attr("text-anchor", "middle")
          .text(function(d) { return formatCount(d.length); });

      g.append("g")
          .attr("class", "axis axis--x")
          .attr("transform", "translate(0," + height + ")")
          .call(d3.axisBottom(x));

      var legend = svg.append("g")
              .attr("class", "legend")
              .attr("transform", "translate(" + (width - 245) + "," + 40 + ")")
              .selectAll("g")
              .data(["Congruent", "Incongruent"])
              .enter().append("g");

          legend.append("text")
              .attr("y", function(d, i) {
                  return i * 30 + 5;
              })
              .attr("x", 200)
              .text(function(d) {
                  return d;
              });

          legend.append("rect")
              .attr("y", function(d, i) {
                  return i * 30 - 8;
              })
              .attr("x", 167)
              .attr("width", 20)
              .attr("height", 20)
              .attr("fill", function(d) {
                  if (d == "Congruent") {
                      return 'rgba(0,0,255,0.6';
                  } else {
                      return 'rgba(255,0,0,0.6';
                  }
              });

      // g.append("path")
      //     .datum(data)
      //     .attr("d", line);

    }
    </script>
  </head>
  <body>
    <h1>Stroop Test</h1>
    <svg width="960" height="500"></svg>
    <script type="text/javascript">
      d3.csv("stroopdata.csv", function(d) {
          d.Congruent = +d.Congruent;
          d.Incongruent = +d.Incongruent;
          return d;
        }, draw);
    </script>
  </body>
</html>

数据如下所示:

Congruent,Incongruent
12.079,19.278
16.791,18.741
9.564,21.214

任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:1)

你在想它。它很简单:

  var line = d3.line()
      .x(function(d) { return x((d.x0 + d.x1)/2); })
      .y(function(d) { return y(d.length); })
      .curve(d3.curveCatmullRom.alpha(0.5));

  g.append("path")
   .attr("d", line(bins1))
   .attr("class", "bins1");

  g.append("path")
   .attr("d", line(bins2))
   .attr("class", "bins2");

运行代码:

&#13;
&#13;
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <style>
    .bar1 rect {
      fill: rgba(0, 0, 255, 0.6);
    }
    
    path.bins1 {
      stroke: rgba(0, 0, 255, 0.6);
      stroke-width: 4px;
      fill: none;
    }
    
    .bar1:hover rect {
      fill: rgba(0, 0, 255, 0.9);
    }
    
    .bar1 text {
      fill: #fff;
      font: 10px sans-serif;
    }
    
    .bar2 rect {
      fill: rgba(255, 0, 0, 0.6);
    }
    
    path.bins2 {
      stroke: rgba(255, 0, 0, 0.6);
      stroke-width: 4px;
      fill: none;
    }
    
    .bar2:hover rect {
      fill: rgba(255, 0, 0, 0.9);
    }
    
    .bar2 text {
      fill: #fff;
      font: 10px sans-serif;
    }
  </style>
  <script src="https://d3js.org/d3.v4.min.js"></script>

  <script>
    function draw(data) {

      var allCongruentData = data.map(function(e) {
        return e.Congruent;
      });
      var allIncongruentData = data.map(function(e) {
        return e.Incongruent;
      });

      var formatCount = d3.format(",.0f");

      var svg = d3.select("svg"),
        margin = {
          top: 10,
          right: 30,
          bottom: 30,
          left: 30
        },
        width = +svg.attr("width") - margin.left - margin.right,
        height = +svg.attr("height") - margin.top - margin.bottom,
        g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");

      var x = d3.scaleLinear()
        .rangeRound([0, width])
        .domain([8, 36]);

      var bins1 = d3.histogram()
        .domain(x.domain())
        .thresholds(x.ticks(40))
        (allCongruentData);

      var line = d3.line()
          .x(function(d) { return x((d.x0 + d.x1)/2); })
          .y(function(d) { return y(d.length); })
          .curve(d3.curveCatmullRom.alpha(0.5));

      var bins2 = d3.histogram()
        .domain(x.domain())
        .thresholds(x.ticks(40))
        (allIncongruentData);

      var y = d3.scaleLinear()
        .domain([0, d3.max(bins1, function(d) {
          return d.length;
        })])
        .range([height, 0]);

      var bar1 = g.selectAll(".bar1")
        .data(bins1)
        .enter().append("g")
        .attr("class", "bar1")
        .attr("transform", function(d) {
          return "translate(" + x(d.x0) + "," + y(d.length) + ")";
        });
        
      g.append("path")
       .attr("d", line(bins1))
       .attr("class", "bins1");

      bar1.append("rect")
        .attr("x", 0.5)
        .attr("width", x(bins1[0].x1) - x(bins1[0].x0) - 1)
        .attr("height", function(d) {
          return height - y(d.length);
        });


      var bar2 = g.selectAll(".bar2")
        .data(bins2)
        .enter().append("g")
        .attr("class", "bar2")
        .attr("transform", function(d) {
          return "translate(" + x(d.x0) + "," + y(d.length) + ")";
        });
        
      g.append("path")
       .attr("d", line(bins2))
       .attr("class", "bins2");

      bar2.append("rect")
        .attr("x", 0.5)
        .attr("width", x(bins2[0].x1) - x(bins2[0].x0) - 1)
        .attr("height", function(d) {
          return height - y(d.length);
        });

      bar1.append("text")
        .attr("dy", ".75em") // why?
        .attr("y", 6)
        .attr("x", (x(bins1[0].x1) - x(bins1[0].x0)) / 2)
        .attr("text-anchor", "middle")
        .text(function(d) {
          return formatCount(d.length);
        });

      bar2.append("text")
        .attr("dy", ".75em") // why?
        .attr("y", 6)
        .attr("x", (x(bins2[0].x1) - x(bins2[0].x0)) / 2)
        .attr("text-anchor", "middle")
        .text(function(d) {
          return formatCount(d.length);
        });

      g.append("g")
        .attr("class", "axis axis--x")
        .attr("transform", "translate(0," + height + ")")
        .call(d3.axisBottom(x));

      var legend = svg.append("g")
        .attr("class", "legend")
        .attr("transform", "translate(" + (width - 245) + "," + 40 + ")")
        .selectAll("g")
        .data(["Congruent", "Incongruent"])
        .enter().append("g");

      legend.append("text")
        .attr("y", function(d, i) {
          return i * 30 + 5;
        })
        .attr("x", 200)
        .text(function(d) {
          return d;
        });

      legend.append("rect")
        .attr("y", function(d, i) {
          return i * 30 - 8;
        })
        .attr("x", 167)
        .attr("width", 20)
        .attr("height", 20)
        .attr("fill", function(d) {
          if (d == "Congruent") {
            return 'rgba(0,0,255,0.6';
          } else {
            return 'rgba(255,0,0,0.6';
          }
        });

      // g.append("path")
      //     .datum(data)
      //     .attr("d", line);

    }
  </script>
</head>

<body>
  <h1>Stroop Test</h1>
  <svg width="960" height="500"></svg>
  <script type="text/javascript">
    
    var data = [];
    for (var i = 0; i < 50; i++){
      data.push({
        Congruent: (Math.random() * (36 - 8)) + 8,
        Incongruent: (Math.random() * (36 - 8)) + 8
      })
    }
    draw(data);
    
    /*
    d3.csv("stroopdata.csv", function(d) {
      d.Congruent = +d.Congruent;
      d.Incongruent = +d.Incongruent;
      return d;
    }, draw);
    */  
  
  </script>
</body>

</html>
&#13;
&#13;
&#13;