web-dev-qa-db-ja.com

D3でのグラフの凡例の追加

D3jsグラフにグラフの凡例を追加することができません。私の現在のアプローチは次のとおりです。

var legend = svg.append("g")
  .attr("class", "legend")
  .attr("x", w - 65)
  .attr("y", 25)
  .attr("height", 100)
  .attr("width", 100);

legend.append("rect")
  .attr("x", w - 65)
  .attr("y", 25)
  .attr("width", 10)
  .attr("height", 10)
  .style("fill", function(d) { return color_hash[dataset.indexOf(d)][1] });

legend.append("text")
  .attr("x", w - 65)
  .attr("y", 25)
  .text(function(d) { return color_hash[dataset.indexOf(d)][0] + ": " + d; });

次に、.legendクラスのスタイルを設定しようとしています。

.legend {
            padding: 5px;
            font: 10px sans-serif;
            background: yellow;
            box-shadow: 2px 2px 1px #888;
        }

しかし、私はあまり運がありません。

凡例をチャートに追加することに慣れている人は、そうするための最良の方法を提供できますか?私はこのオンラインのための多くのリソースを見つけていません。

これが私のグラフ全体です: http://jsbin.com/ewiwag/2/edit

41
darko

凡例を構成するノード(長方形とテキスト要素)にデータをバインドする必要があります。

現在、長方形のスタイルを設定しようとするとエラーが発生します:

Uncaught TypeError: Cannot read property '1' of undefined 

理由:バインドされたデータがない

legend.append("rect")
      /*...*/
      .style("fill", function(d) { 
         // d <---- is undefined
         return color_hash[dataset.indexOf(d)][1] 
      });

D3はデータ変換に焦点を合わせ、選択に作用することに注意してください。したがって、最初にノードのセットを選択し、次にデータをバインドします

legend.selectAll('rect')
      .data(dataset)
      .enter()

enterを使用して選択範囲を入力すると、ノードを追加してプロパティを動的に適用できます。 yプロパティを設定するときにiカウンターを渡して整数を乗算すると、他の上に長方形が作成されないように注意してください。

  /*.....*/
      .append("rect")
      .attr("x", w - 65)
      .attr("y", function(d, i){ return i *  20;})
      .attr("width", 10)
      .attr("height", 10)
      .style("fill", function(d) { 
         var color = color_hash[dataset.indexOf(d)][1];
         return color;
      });

修正された例を次に示します。 http://jsbin.com/ubafur/

37
jaime

わかりました、それをする1つの方法はここにあります: http://jsbin.com/isuris/1/edit

申し訳ありませんが、すべてを説明するには変更が多すぎます。あなたがそれを理解できるかどうかを確認してください。ご質問がある場合は、コメント欄で質問してください。回答を修正します。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <script type="text/javascript" src="http://mbostock.github.com/d3/d3.js"></script>
    <style type="text/css">

      .axis path,
      .axis line {
        fill: none;
        stroke: black;
        shape-rendering: crispEdges;
      }

      .axis text {
        font-family: sans-serif;
        font-size: 11px;
      }

      .y1 {
        fill: white;
        stroke: orange;
        stroke-width: 1.5px;
      }

      .y2 {
        fill: white;
        stroke: red;
        stroke-width: 1.5px;
      }

      .y3 {
        fill: white;
        stroke: steelblue;
        stroke-width: 1.5px;
      }

      .line {
        fill: none;
        stroke-width: 1.5px;
      }

      div.tooltip {
              position: absolute;
              text-align: center;
              width: 50px;
              height: 10px;
              padding: 5px;
              font: 10px sans-serif;
              background: whiteSmoke;
              border: solid 1px #aaa;
              pointer-events: none;
              box-shadow: 2px 2px 1px #888;
            }

            .legend {
              padding: 5px;
              font: 10px sans-serif;
              background: yellow;
              box-shadow: 2px 2px 1px #888;
            }

            .title {
              font: 13px sans-serif;
            }

    </style>
  </head>
  <body>
    <script type="text/javascript">

    //Width and height
    var w = 500;
    var h = 300;
    var padding = 50;

    var now = d3.time.hour.utc(new Date);
    var dataset = [ [ ],[ ] ];
    dataset[0].Push({x: d3.time.hour.utc.offset(now, -5), y: 0});
    dataset[0].Push({x: d3.time.hour.utc.offset(now, -4), y: 0});
    dataset[0].Push({x: d3.time.hour.utc.offset(now, -3), y: 2});
    dataset[0].Push({x: d3.time.hour.utc.offset(now, -2), y: 0});
    dataset[0].Push({x: d3.time.hour.utc.offset(now, -1), y: 0});
    dataset[0].Push({x: now, y: 0});

    dataset[1].Push({x: d3.time.hour.utc.offset(now, -5), y: 3});
    dataset[1].Push({x: d3.time.hour.utc.offset(now, -4), y: 1});
    dataset[1].Push({x: d3.time.hour.utc.offset(now, -3), y: 3});
    dataset[1].Push({x: d3.time.hour.utc.offset(now, -2), y: 1});
    dataset[1].Push({x: d3.time.hour.utc.offset(now, -1), y: 5});
    dataset[1].Push({x: now, y: 1});

    var color_hash = {  0 : ["Apple", "green"],
              1 : ["mango", "orange"],
              2 : ["cherry", "red"]
            }                      

    // Define axis ranges & scales        
    var yExtents = d3.extent(d3.merge(dataset), function (d) { return d.y; });
    var xExtents = d3.extent(d3.merge(dataset), function (d) { return d.x; });

  var xScale = d3.time.scale()
         .domain([xExtents[0], xExtents[1]])
         .range([padding, w - padding * 2]);

  var yScale = d3.scale.linear()
         .domain([0, yExtents[1]])
         .range([h - padding, padding]);


  // Create SVG element
  var svg = d3.select("body")
      .append("svg")
      .attr("width", w)
      .attr("height", h);


  // Define lines
  var line = d3.svg.line()
         .x(function(d) { return x(d.x); })
         .y(function(d) { return y(d.y1, d.y2, d.y3); });

  var pathContainers = svg.selectAll('g.line')
  .data(dataset);

  pathContainers.enter().append('g')
  .attr('class', 'line')
  .attr("style", function(d) {
    return "stroke: " + color_hash[dataset.indexOf(d)][1]; 
  });

  pathContainers.selectAll('path')
  .data(function (d) { return [d]; }) // continues the data from the pathContainer
  .enter().append('path')
    .attr('d', d3.svg.line()
      .x(function (d) { return xScale(d.x); })
      .y(function (d) { return yScale(d.y); })
    );

  // add circles
  pathContainers.selectAll('circle')
  .data(function (d) { return d; })
  .enter().append('circle')
  .attr('cx', function (d) { return xScale(d.x); })
  .attr('cy', function (d) { return yScale(d.y); })
  .attr('r', 3); 

    //Define X axis
  var xAxis = d3.svg.axis()
          .scale(xScale)
          .orient("bottom")
          .ticks(5);

  //Define Y axis
  var yAxis = d3.svg.axis()
          .scale(yScale)
          .orient("left")
          .ticks(5);

  //Add X axis
  svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(0," + (h - padding) + ")")
  .call(xAxis);

  //Add Y axis
  svg.append("g")
  .attr("class", "axis")
  .attr("transform", "translate(" + padding + ",0)")
  .call(yAxis);

  // Add title    
  svg.append("svg:text")
       .attr("class", "title")
     .attr("x", 20)
     .attr("y", 20)
     .text("Fruit Sold Per Hour");


  // add legend   
  var legend = svg.append("g")
    .attr("class", "legend")
    .attr("x", w - 65)
    .attr("y", 25)
    .attr("height", 100)
    .attr("width", 100);

  legend.selectAll('g').data(dataset)
      .enter()
      .append('g')
      .each(function(d, i) {
        var g = d3.select(this);
        g.append("rect")
          .attr("x", w - 65)
          .attr("y", i*25)
          .attr("width", 10)
          .attr("height", 10)
          .style("fill", color_hash[String(i)][1]);

        g.append("text")
          .attr("x", w - 50)
          .attr("y", i * 25 + 8)
          .attr("height",30)
          .attr("width",100)
          .style("fill", color_hash[String(i)][1])
          .text(color_hash[String(i)][0]);

      });
    </script>
  </body>
</html>
12
meetamit