【问题标题】:How to add titles to multiple pie charts, while having a single legend?如何在具有单个图例的同时向多个饼图添加标题?
【发布时间】:2017-02-21 16:33:14
【问题描述】:

我有这些数据:

var data = [
  [
    {"piece_value":76.34,name:"AG",group:"G1"},
    {"piece_value":69.05,name:"A3",group:"G1"},
    {"piece_value":275.19,name:"A4",group:"G1"}
  ],
  [
    {"piece_value":69.93,name:"AG",group:"G2"},
    {"piece_value":61.50,name:"A3",group:"G2"},
    {"piece_value":153.31,name:"A4",group:"G2"}
  ],
  [
    {"piece_value":67.48,name:"AG",group:"G3"},
    {"piece_value":58.03,name:"A3",group:"G3"},
    {"piece_value":145.93,name:"A4",group:"G3"}
  ]
];

我有 3 个饼图(参见代码 sn-p)。我想将相应的group 值放在每个饼图的顶部,并将图例移动到右侧(垂直图例)。问题是现在我有 3 个图例(每个饼图一个),但实际上它总是相同的图例。因此,我不想将其复制 3 次,而是希望在右侧有一个图例,同时将 group 值作为标题。 如何做到这一点?

var data = [
  [
    {"piece_value":76.34,name:"AG",group:"G1"},
    {"piece_value":69.05,name:"A3",group:"G1"},
    {"piece_value":275.19,name:"A4",group:"G1"}
  ],
  [
    {"piece_value":69.93,name:"AG",group:"G2"},
    {"piece_value":61.50,name:"A3",group:"G2"},
    {"piece_value":153.31,name:"A4",group:"G2"}
  ],
  [
    {"piece_value":67.48,name:"AG",group:"G3"},
    {"piece_value":58.03,name:"A3",group:"G3"},
    {"piece_value":145.93,name:"A4",group:"G3"}
  ]
];

var m = 10,
    r = 90,
    z = d3.scale.category20c();

var svg = d3.select("body").selectAll("svg")
    .data(data)
    .enter().append("svg")
    .attr("width", (r + m) * 2)
    .attr("height", (r + m) * 2)
    .append("g")
    .attr("transform", "translate(" + (r + m) + "," + (r + m) + ")");

var pie = d3.layout.pie()
    .sort(null)
    .value(function(d) {
        return d.piece_value;
    });

var arc = d3.svg.arc()
    .innerRadius(r / 2.2)
    .outerRadius(r/1.2)

svg.selectAll("path")
    .data(pie)
    .enter().append("path")
    .attr("d", arc)
    .style("fill", function(d, i) {
        return z(i);
    });

svg.selectAll("foo")
    .data(pie)
    .enter()
    .append("text")
    .attr("text-anchor", "middle")
    .attr("transform", d => "translate(" + arc.centroid(d) + ")")
    .text(d => d.data.piece_value);
		
svg.selectAll("foo")
    .data(d=>d)
    .enter()
    .append("text")
		.attr("transform", (d,i)=>"translate(" + (-r + 2.5*m + (i * 70)) + "," +  (-r + m) + ")")
		.text(d=>d.name);
		
svg.selectAll("foo")
    .data(d=>d)
    .enter()
    .append("rect")
		.attr("transform", (d,i)=>"translate(" + (-r + m + (i * 70)) + "," +  (-r) + ")")
		.attr("width", 10)
		.attr("height", 10)
		.style("fill", (d, i) => z(i));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

【问题讨论】:

    标签: javascript d3.js svg


    【解决方案1】:

    每个甜甜圈都有一个图例背后的想法是它允许拥有不同的数据(关于分类变量)。然而,既然你说你只想要一个图例,我假设每个图表的分类变量都是相同的。既然如此,我们可以新建一个数据数组……

    var legendData = data[0].map(d=>d.name);
    

    ...使用任何索引(同样,数组对于分类变量是相同的),而不是绘制另一个 SVG,我们可以简单地使用 HTML 创建图例:

    var legendDiv = d3.select("#legend");
    
    var legendRow = legendDiv.selectAll("foo")
        .data(legendData)
        .enter()
        .append("div")
        .style("margin-bottom", "2px");
    
    legendRow.append("div")
        .html("&nbsp")
        .attr("class", "rect")
        .style("background-color", (d, i) => z(i));
    
    legendRow.append("div")
        .html(d => d);
    

    这是一个带有垂直图例的演示:

    var data = [
      [
        {"piece_value":76.34,name:"AG",group:"G1"},
        {"piece_value":69.05,name:"A3",group:"G1"},
        {"piece_value":275.19,name:"A4",group:"G1"}
      ],
      [
        {"piece_value":69.93,name:"AG",group:"G2"},
        {"piece_value":61.50,name:"A3",group:"G2"},
        {"piece_value":153.31,name:"A4",group:"G2"}
      ],
      [
        {"piece_value":67.48,name:"AG",group:"G3"},
        {"piece_value":58.03,name:"A3",group:"G3"},
        {"piece_value":145.93,name:"A4",group:"G3"}
      ]
    ];
    
    var m = 10,
        r = 90,
        z = d3.scale.category20c();
    
    var svg = d3.select("body").selectAll("svg")
        .data(data)
        .enter().append("svg")
        .attr("width", (r + m) * 2)
        .attr("height", (r + m) * 2)
        .append("g")
        .attr("transform", "translate(" + (r + m) + "," + (r + m) + ")");
    
    var pie = d3.layout.pie()
        .sort(null)
        .value(function(d) {
            return d.piece_value;
        });
    
    var arc = d3.svg.arc()
        .innerRadius(r / 2)
        .outerRadius(r/1)
    
    svg.selectAll("path")
        .data(pie)
        .enter().append("path")
        .attr("d", arc)
        .style("fill", function(d, i) {
            return z(i);
        });
    
    svg.selectAll("foo")
        .data(pie)
        .enter()
        .append("text")
        .attr("text-anchor", "middle")
        .attr("transform", d => "translate(" + arc.centroid(d) + ")")
        .text(d => d.data.piece_value);
    		
    var legendData = data[0].map(d=>d.name);
    
    var legendDiv = d3.select("#legend");
    
    var legendRow = legendDiv.selectAll("foo")
    	  .data(legendData)
        .enter()
        .append("div")
    		.style("margin-bottom", "2px");
    
    legendRow.append("div")
    		.html("&nbsp")
    		.attr("class", "rect")
    		.style("background-color", (d, i) => z(i));
    		
    legendRow.append("div")
    		.html(d=>d);
    		
    .rect {
    	width: 20px;
    	float: left;
    	margin-right: 10px;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <div id="legend">Legend:</div>

    PS:你说你想要右边的图例。为此,只需并排创建 2 个 div:在左侧附加 SVG,在右侧附加图例。我会把这个作为作业留给你。

    PS2:请注意scale.category20 按照先到先得的原则工作。因此,为了使图例准确,内部数组中分类变量的顺序必须相同。

    【讨论】:

      【解决方案2】:

      我只想为图例添加一个完全独立的 svg。此外,除非您需要不同的 svg,否则您可以考虑为每个饼图添加一组,为图例添加一组(但在翻译方面需要更多工作)。 出于性能考虑,我也会坚持使用单个绑定进行输入,并将其存储在局部变量中。 最后,我会为每个图例项创建一个组,以避免重复翻译代码:

      var data = [
        [
          {"piece_value":76.34,name:"AG",group:"G1"},
          {"piece_value":69.05,name:"A3",group:"G1"},
          {"piece_value":275.19,name:"A4",group:"G1"}
        ],
        [
          {"piece_value":69.93,name:"AG",group:"G2"},
          {"piece_value":61.50,name:"A3",group:"G2"},
          {"piece_value":153.31,name:"A4",group:"G2"}
        ],
        [
          {"piece_value":67.48,name:"AG",group:"G3"},
          {"piece_value":58.03,name:"A3",group:"G3"},
          {"piece_value":145.93,name:"A4",group:"G3"}
        ]
      ];
      
      var m = 10,
          r = 90,
          z = d3.scale.category20c();
      
      var svg = d3.select("body")
          .selectAll("svg")
          .data(data)
          .enter()
          .append("svg")
          .attr("width", (r + m) * 2)
          .attr("height", (r + m) * 2)
          .append("g")
          .attr("transform", "translate(" + (r + m) + "," + (r + m) + ")");
      
      var pie = d3.layout.pie()
          .sort(null)
          .value(function(d) {
              return d.piece_value;
          });
      
      var arc = d3.svg.arc()
          .innerRadius(r / 2.2)
          .outerRadius(r/1.2)
      
      svg.selectAll("path")
          .data(pie)
          .enter()
          .append("path")
          .attr("d", arc)
          .style("fill", function(d, i) {
              return z(i);
          });
      
       var foo = svg.selectAll("foo")
          .data(pie)
          .enter();
       foo.append("text")
          .attr("text-anchor", "middle")
          .attr("transform", d => "translate(" + arc.centroid(d) + ")")
          .text(d => d.data.piece_value);
      	//the legend
       var legendGroup =    d3.select("body")
            .append('svg')
            .append('g')
            .classed('legend',true);
       var enterLegend = legendGroup
          .selectAll('.legend-item')
          .data(pie)
          .enter();
       var legendItem = enterLegend
          .append('g')
          .classed('legend-item',true)
          .attr("transform", (d,i)=>"translate(" + (-r + (i * 70)) + "," +  (-r + m) + ")");
       legendItem.append("text")
               .text(d=>d.name);
      		
       legendItem.append("rect")
      		.attr('x',10)
      		.attr("width", 10)
      		.attr("height", 10)
      		.style("fill", (d, i) => z(i));
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

      我没有运行代码,但我希望你明白。

      【讨论】:

        猜你喜欢
        • 2020-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多