【问题标题】:Loop over JSON data to create d3 pie charts循环 JSON 数据以创建 d3 饼图
【发布时间】:2017-05-30 21:21:45
【问题描述】:

我已经成功地使用 d3 和 JSON 创建了我的第一个饼图,但我很难让多个饼图出现。我查看了许多示例,包括 Mike Bostock's donut-multiples,看来我的代码中需要一个 for-each 循环。

这是我的程序的简化版本,它生成一个饼图而不是两个:

<!doctype html>
<html>
<head>
    <title>Pie Chart Test</title>
    <meta charset="UTF-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
</head>

<style>
.arc path {
    stroke: white;
}
</style>

<body>
    <script>
        var width = 300,
            height = 300,
            radius = Math.min(width, height) / 2;

        var arc = d3.svg.arc()
            .outerRadius(radius)
            .innerRadius(radius - (radius / 2));

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

        var svg = d3.select("body").append("svg")
            .attr("width", width)
            .attr("height", height)
            .append("g")
            .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

        d3.json("data.json", function(error, data) {
            if (error) throw error;

            node = data.data[0].pie1.results;

            var g = svg.selectAll(".arc")
                .data(pie(node))
                .enter().append("g")
                .attr("class", "arc")

                g.append("path")
                    .attr("d", arc)
                    .style("fill", function(d) { 
                        if (d.data.failures > 0) {
                            return "#d63535";
                        } else {
                            return "#22c12d";
                        }
                    });
        });
    </script>
</body>
</html>

这是填充图表的 JSON:

    {"data":[
    {"pie1": {
        "results": [
            {"ratio": 0.04, "total": 7, "failures": 1},
            {"ratio": 0.04, "total": 8, "failures": 0},
            {"ratio": 0.04, "total": 9001, "failures": 0}
        ]}
    },
    {"pie2": {
        "results": [
            {"ratio": 0.04, "total": 10, "failures": 0},
            {"ratio": 0.04, "total": 11, "failures": 1},
            {"ratio": 0.04, "total": 12, "failures": 1}
        ]}
    }
]}

【问题讨论】:

    标签: javascript json d3.js charts pie-chart


    【解决方案1】:

    看来我的代码中需要一个 for-each 循环

    一般来说,d3中可以避免for each循环。 d3 的大多数规范示例都避免使用它们。

    您可以使用标准的 d3 enter 选择来代替 for-each 循环,为数据数组中的每个项目创建一个 svg 元素(即每个饼图一个 svg)。这会将每个饼图的数据绑定到其各自的 svg:

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

    现在您可以使用绑定数据为每个 svg 创建饼图:

        var g = svg.selectAll(".arc")
            .data(function(d,i) { return pie(d["pie"+(i+1)].results) })
            .enter().append("g")
            .attr("class", "arc")
    
            g.append("path")
             .attr("d", arc)
             .style("fill", function(d) { return (d.data.failures > 0) ? "#d63535" : "#22c12d"; });
    

    所有这些看起来像:

    var data  = {"data":[
        {"pie1": {
            "results": [
                {"ratio": 0.04, "total": 7, "failures": 1},
                {"ratio": 0.04, "total": 8, "failures": 0},
                {"ratio": 0.04, "total": 9001, "failures": 0}
            ]}
        },
        {"pie2": {
            "results": [
                {"ratio": 0.04, "total": 10, "failures": 0},
                {"ratio": 0.04, "total": 11, "failures": 1},
                {"ratio": 0.04, "total": 12, "failures": 1}
            ]}
        }
    ]};
    	
    	     var width = 300,
                height = 300,
                radius = Math.min(width, height) / 2;
    
            var arc = d3.svg.arc()
                .outerRadius(radius)
                .innerRadius(radius - (radius / 2));
    
            var pie = d3.layout.pie()
                .sort(null)
                .value(function(d) { return d.ratio; });
    
            var svg = d3.select("body").selectAll("svg")
    		   .data(data.data)
    		   .enter()
    		   .append("svg")
               .attr("width", width)
               .attr("height", height)
               .append("g")
               .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    	    var g = svg.selectAll(".arc")
                .data(function(d,i) { return pie(d["pie"+(i+1)].results) })
                .enter().append("g")
                .attr("class", "arc")
    
                g.append("path")
                 .attr("d", arc)
                 .style("fill", function(d) { return (d.data.failures > 0) ? "#d63535" : "#22c12d"; });
    .arc path {
        stroke: white;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"&gt;&lt;/script&gt;

    当然,您的数据结构确实使事情有些复杂。我已经将它保存在上面的 sn-p 中,但稍微改变一下将有助于简化代码:

    var data = [
           {
    	    "name":"pie1",
            "results": [
                {"ratio": 0.04, "total": 7, "failures": 1},
                {"ratio": 0.04, "total": 8, "failures": 0},
                {"ratio": 0.04, "total": 9001, "failures": 0}
    			]
    		},
           {
    	    "name":"pie2",
            "results": [
                {"ratio": 0.04, "total": 10, "failures": 0},
                {"ratio": 0.04, "total": 11, "failures": 1},
                {"ratio": 0.04, "total": 12, "failures": 1}
            ]
    		}
           ]
    	
    	     var width = 300,
                height = 300,
                radius = Math.min(width, height) / 2;
    
            var arc = d3.svg.arc()
                .outerRadius(radius)
                .innerRadius(radius - (radius / 2));
    
            var pie = d3.layout.pie()
                .sort(null)
                .value(function(d) { return d.ratio; });
    
            var svg = d3.select("body").selectAll("svg")
    		   .data(data)
    		   .enter()
    		   .append("svg")
               .attr("width", width)
               .attr("height", height)
               .append("g")
               .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
    
    	    var g = svg.selectAll(".arc")
                .data(function(d,i) { return pie(d.results) })
                .enter().append("g")
                .attr("class", "arc")
    
                g.append("path")
                 .attr("d", arc)
                 .style("fill", function(d) { return (d.data.failures > 0) ? "#d63535" : "#22c12d"; });
    .arc path {
        stroke: white;
    }
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"&gt;&lt;/script&gt;

    第二个 sn-p 不需要访问数据数组中每个元素的唯一属性。如果每个数据元素都有唯一标识符,只需将其分配给数据数组中每个项目的通用命名属性即可。

    您不必将数据绑定到多个 svg 元素,也可以使用多个 g 元素(例如)。

    【讨论】:

      【解决方案2】:

      你有代码node = data.data[0].pie1.results;

      但你对 pie2 什么都不做。

      如果您想对其进行硬编码,您可以使用node2 = data.data[0].pie2.results;,但最好尝试以编程方式进行。

      类似

      for( pie in data.data[0] ){
          node = pie.results;
      
          var g = svg.selectAll(".arc")
              .data(pie(node))
              .enter().append("g")
              .attr("class", "arc")
          g.append("path")
              .attr("d", arc)
              .style("fill", function(d) { 
                  if (d.data.failures > 0) {
                      return "#d63535";
                  } else {
                      return "#22c12d";
              }
          });
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多