循环 JSON 数据以创建 d3 饼图

Loop over JSON data to create d3 pie charts

我已经成功地使用 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}
        ]}
    }
]}

您有密码 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";
        }
    });
}

it appears I need a for-each loop in my code

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

您可以使用标准的 d3 输入选择来为数据数组中的每个项目创建一个 svg 元素(即每个饼图一个 svg),而不是 for-each 循环。这将每个饼图的数据绑定到其各自的 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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>

当然,您的数据结构确实使事情复杂化了一点。我将它保留在上面的代码片段中,但稍作更改将有助于简化代码:

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;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>

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

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