循环处理JSON数据以创建d3饼图 [英] Loop over JSON data to create d3 pie charts

查看:185
本文介绍了循环处理JSON数据以创建d3饼图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功地使用d3和JSON创建了第一个饼图,但我一直在努力使多个饼图无法显示.我查看了许多示例,包括迈克·波斯托克的甜甜圈倍数,看来我需要一个我的代码中的for-each循环.

I've succeeded in creating my first pie chart with d3 and JSON, but I'm struggling to get more than one pie chart to appear. I've reviewed numerous examples, including Mike Bostock's donut-multiples, and it appears I need a for-each loop in my code.

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

Here's a simplified version of my program which produces one pie chart instead of two:

<!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:

and here is the JSON that populates the chart:

    {"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}
        ]}
    }
]}

推荐答案

似乎我的代码中需要一个for-each循环

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

通常来说,对于d3中的每个循环,都可以避免. d3的大多数规范示例都避免使用它们.

Generally speaking, for each loops can be avoided in d3. Most cannonical examples of d3 avoid use of them.

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

Instead of a for-each loop, you can use a standard d3 enter selection to create an svg element for each item in your data array (ie one svg for each pie chart). This binds the data for each pie chart to its respective 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创建饼图:

Now you can create pie charts for each svg using the bound data:

    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>

当然,您的数据结构确实使事情复杂化了一点.我将其保留在上面的代码段中,但是对其进行一些更改将有助于简化代码:

Of course, your data structure does complicate things a little. I've kept it in the snippet above, but changing it a little would help simplify the code:

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>

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

This second snippet doesn't require accessing a unique property in each element in your data array. If you have a unique identifier for each data element, just assign it to a commonly named property for each item in the data array.

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

You don't have to bind the data to multiple svg elements, you could use multiple g elements too (for example).

这篇关于循环处理JSON数据以创建d3饼图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆