D3图表值未分组(通过JSON加载)

时间:2018-07-17 13:21:16

标签: javascript json d3.js

我有一个JSON查询,我正在使用D3图表显示数据。似乎分组(国家/地区)无效。对于每个国家/地区(例如加拿大),我们可以设置多条路线。部分代码:

data.forEach(function (a) {
    groups[a.value] = groups[a.value] || [];
    groups[a.value].push(a);    
});

result = Object.keys(groups).reduce(function (r, k) {
    return r.concat(groups[k]);
}, []);

理想情况下,我想通过更改脚本来完成这项工作。第二种解决方案是更改JSON的格式(操作)。我正在尝试着重于第一个解决方案...代码段在这里:

      var json_data= {"headers":["Dimension 1","Metric 1","Metric 2"],"rows":[["Australia",174,23],["Canada",502,17],["France",242,37],["Germany",102,42],["United Kingdom",126,44],["United States",1246,47],["Australia",680,80],["Canada",1241,66],["Canada",1241,66],["France",150,30],["Germany",244,22],["United Kingdom",501,9],["United States",4960,41],["Australia",9,8],["Canada",3655,70],["France",1654,95],["Germany",1190,36],["United Kingdom",1222,38],["United States",7941,53],["Australia",6829,56],["Canada",1664,75],["France",2995,88],["Germany",1487,100],["United Kingdom",9245,29],["United States",9008,66],["Australia",9376,7],["Canada",1531,31],["France",5421,22],["Germany",6975,41],["United Kingdom",4320,100],["United States",3200,41],["Australia",6688,41],["Canada",699,42],["France",5403,70],["Germany",6377,49],["United Kingdom",2471,14],["United States",6650,4],["Australia",865,70],["Canada",511,20],["France",981,36],["Germany",57,10],["United Kingdom",675,38],["United States",40,72],["Australia",400,63],["Canada",971,90],["France",357,93],["Germany",820,40],["United Kingdom",520,32],["United States",448,24],["Australia",513,40],["Canada",977,8],["France",118,84],["Germany",161,29],["United Kingdom",239,89],["United States",327,79]]};
      var headers = json_data.headers;
      var platform_data = json_data.rows;
      var data = [];
      var metric = 0;
      for (var i in platform_data)
        {
          var dimension = platform_data[i][0];
          metric = (platform_data[i][1]).toFixed(0);
          object = { label: dimension, value: metric};
          data.push(object);
        }

//Sorting
var data = data,
    groups = Object.create(null),
    result = [];

data.forEach(function (a) {
    groups[a.value] = groups[a.value] || [];
    groups[a.value].push(a);    
});

result = Object.keys(groups).reduce(function (r, k) {
    return r.concat(groups[k]);
}, []);


//Descending - Reverse JSON order
var objAssetSelection = result.reverse();
data = objAssetSelection;

//D3 Code

        var div = d3.select("body").append("div").attr("class", "toolTip");
    
        var axisMargin = 20,
                margin = 40,
                valueMargin = 4,
                width = parseInt(d3.select('body').style('width'), 10),
                height = parseInt(d3.select('body').style('height'), 10),
                barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
                barPadding = (height-axisMargin-margin*2)*0.6/data.length,
                data, bar, svg, scale, xAxis, labelWidth = 0;
    
        max = d3.max(data, function(d) { return d.value; });
    
        svg = d3.select('body')
                .append("svg")
                .attr("width", width)
                .attr("height", height);
    
    
        bar = svg.selectAll("g")
                .data(data)
                .enter()
                .append("g");
    
        bar.attr("class", "bar")
                .attr("cx",0)
                .attr("transform", function(d, i) {
                    return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
                });
    
        bar.append("text")
                .attr("class", "label")
                .attr("y", barHeight / 2)
                .attr("dy", ".35em") //vertical align middle
                .text(function(d){
                    return d.label;
                }).each(function() {
            labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
        });
    
        scale = d3.scale.linear()
                .domain([0, max])
                .range([0, width - margin*2 - labelWidth]);
    
        xAxis = d3.svg.axis()
                .scale(scale)
                .tickSize(-height + 2*margin + axisMargin)
                .orient("bottom");
    
        bar.append("rect")
                .attr("transform", "translate("+labelWidth+", 0)")
                .attr("height", barHeight)
                .attr("width", function(d){
                    return scale(d.value);
                });
    
        bar.append("text")
                .attr("class", "value")
                .attr("y", barHeight / 2)
                .attr("dx", -valueMargin + labelWidth) //margin right
                .attr("dy", ".35em") //vertical align middle
                .attr("text-anchor", "end")
                .text(function(d){
                    return (d.value);
                })
                .attr("x", function(d){
                    var width = this.getBBox().width;
                    return Math.max(width + valueMargin, scale(d.value));
                });
    
        bar
                .on("mousemove", function(d){
                    div.style("left", d3.event.pageX+10+"px");
                    div.style("top", d3.event.pageY-25+"px");
                    div.style("display", "inline-block");
                    div.html((d.label)+"<br>"+(d.value));
                });
        bar
                .on("mouseout", function(d){
                    div.style("display", "none");
                });
    
        svg.insert("g",":first-child")
                .attr("class", "axisHorizontal")
                .attr("transform", "translate(" + (margin + labelWidth) + ","+ (height - axisMargin - margin)+")")
                .call(xAxis);
@import url('https://fonts.googleapis.com/css?family=Roboto');

body {
        font-family: "Roboto"!important;
        width: 100%;
        height: 500px;
        position: relative;
    }

    svg {
        width: 100%;
        height: 100%;
        position: center;
    }

    .toolTip {
        position: absolute;
        display: none;
        width: auto;
        height: auto;
        background: none repeat scroll 0 0 white;
        border: 0 none;
        border-radius: 8px 8px 8px 8px;
        box-shadow: -3px 3px 15px #888888;
        color: black;
        font: 12px sans-serif;
        padding: 5px;
        text-align: center;
    }

    text {
        font: 10px sans-serif;
        color: white;
    }
    text.value {
        font-size: 100%;
        fill: white;
    }

    .axisHorizontal path{
        fill: none;
    }

    .axisHorizontal .tick line {
        stroke-width: 1;
        stroke: rgba(0, 0, 0, 0.2);
    }

    .bar {
        fill: steelblue;
        fill-opacity: .9;
    }
<script src="https://d3js.org/d3.v3.min.js"></script>

1 个答案:

答案 0 :(得分:1)

分组代码不正确。如果您在分组数据之后管理日志data,则它是相同的未分组数据。

为更好地分组,您可以查看d3.nest。这是使用d3.nest的分组代码(根据 label 分组数据并使用d3.sumd3.sum)对值求和:

var nested_data = d3.nest()
                    .key(function(d) { return d.label; })
                    .rollup(function (d) { 
                      return d3.sum(d, function(v) { return +v.value;})
                    }).entries(data);

为了不影响您的其余代码,我通过以下方式将此nested_data映射为原始格式:

data = nested_data.map(function(row) {
  return {label: row.key, value: row.values};
});

编辑:添加排序代码

data.sort(function(a, b) { return a.value > b.value ? -1 : a.value === b.value ? 0 : 1; });

使用上面的嵌套/分组,这是一个代码段:

var json_data= {"headers":["Dimension 1","Metric 1","Metric 2"],"rows":[["Australia",174,23],["Canada",502,17],["France",242,37],["Germany",102,42],["United Kingdom",126,44],["United States",1246,47],["Australia",680,80],["Canada",1241,66],["Canada",1241,66],["France",150,30],["Germany",244,22],["United Kingdom",501,9],["United States",4960,41],["Australia",9,8],["Canada",3655,70],["France",1654,95],["Germany",1190,36],["United Kingdom",1222,38],["United States",7941,53],["Australia",6829,56],["Canada",1664,75],["France",2995,88],["Germany",1487,100],["United Kingdom",9245,29],["United States",9008,66],["Australia",9376,7],["Canada",1531,31],["France",5421,22],["Germany",6975,41],["United Kingdom",4320,100],["United States",3200,41],["Australia",6688,41],["Canada",699,42],["France",5403,70],["Germany",6377,49],["United Kingdom",2471,14],["United States",6650,4],["Australia",865,70],["Canada",511,20],["France",981,36],["Germany",57,10],["United Kingdom",675,38],["United States",40,72],["Australia",400,63],["Canada",971,90],["France",357,93],["Germany",820,40],["United Kingdom",520,32],["United States",448,24],["Australia",513,40],["Canada",977,8],["France",118,84],["Germany",161,29],["United Kingdom",239,89],["United States",327,79]]};
      var headers = json_data.headers;
      var platform_data = json_data.rows;
      var data = [];
      var metric = 0;
      for (var i in platform_data)
        {
          var dimension = platform_data[i][0];
          metric = (platform_data[i][1]).toFixed(0);
          object = { label: dimension, value: metric};
          data.push(object);
        }

//Sorting
var data = data,
    groups = Object.create(null),
    result = [];

/* data.forEach(function (a) {
    groups[a.value] = groups[a.value] || [];
    groups[a.value].push(a);    
});

result = Object.keys(groups).reduce(function (r, k) {
    return r.concat(groups[k]);
}, []); */


var nested_data = d3.nest()
		    .key(function(d) { return d.label; })
                    .rollup(function (d) { 
                      return d3.sum(d, function(v) { return +v.value;})
                    }).entries(data);
                      
data = nested_data.map(function(row) {
	return {label: row.key, value: row.values};
}).sort(function(a, b) { return a.value > b.value ? -1 : a.value === b.value ? 0 : 1; });
//Descending - Reverse JSON order
/* var objAssetSelection = result.reverse();
data = objAssetSelection;
 */
//D3 Code

        var div = d3.select("body").append("div").attr("class", "toolTip");
    
        var axisMargin = 20,
                margin = 40,
                valueMargin = 4,
                width = parseInt(d3.select('body').style('width'), 10),
                height = parseInt(d3.select('body').style('height'), 10),
                barHeight = (height-axisMargin-margin*2)* 0.4/data.length,
                barPadding = (height-axisMargin-margin*2)*0.6/data.length,
                data, bar, svg, scale, xAxis, labelWidth = 0;
    
        max = d3.max(data, function(d) { return d.value; });
    
        svg = d3.select('body')
                .append("svg")
                .attr("width", width)
                .attr("height", height);
    
    
        bar = svg.selectAll("g")
                .data(data)
                .enter()
                .append("g");
    
        bar.attr("class", "bar")
                .attr("cx",0)
                .attr("transform", function(d, i) {
                    return "translate(" + margin + "," + (i * (barHeight + barPadding) + barPadding) + ")";
                });
    
        bar.append("text")
                .attr("class", "label")
                .attr("y", barHeight / 2)
                .attr("dy", ".35em") //vertical align middle
                .text(function(d){
                    return d.label;
                }).each(function() {
            labelWidth = Math.ceil(Math.max(labelWidth, this.getBBox().width));
        });
    
        scale = d3.scale.linear()
                .domain([0, max])
                .range([0, width - margin*2 - labelWidth]);
    
        xAxis = d3.svg.axis()
                .scale(scale)
                .tickSize(-height + 2*margin + axisMargin)
                .orient("bottom");
    
        bar.append("rect")
                .attr("transform", "translate("+labelWidth+", 0)")
                .attr("height", barHeight)
                .attr("width", function(d){
                    return scale(d.value);
                });
    
        bar.append("text")
                .attr("class", "value")
                .attr("y", barHeight / 2)
                .attr("dx", -valueMargin + labelWidth) //margin right
                .attr("dy", ".35em") //vertical align middle
                .attr("text-anchor", "end")
                .text(function(d){
                    return (d.value);
                })
                .attr("x", function(d){
                    var width = this.getBBox().width;
                    return Math.max(width + valueMargin, scale(d.value));
                });
    
        bar
                .on("mousemove", function(d){
                    div.style("left", d3.event.pageX+10+"px");
                    div.style("top", d3.event.pageY-25+"px");
                    div.style("display", "inline-block");
                    div.html((d.label)+"<br>"+(d.value));
                });
        bar
                .on("mouseout", function(d){
                    div.style("display", "none");
                });
    
        svg.insert("g",":first-child")
                .attr("class", "axisHorizontal")
                .attr("transform", "translate(" + (margin + labelWidth) + ","+ (height - axisMargin - margin)+")")
                .call(xAxis);
body {
        font-family: "Roboto"!important;
        width: 100%;
        height: 500px;
        position: relative;
    }

    svg {
        width: 100%;
        height: 100%;
        position: center;
    }

    .toolTip {
        position: absolute;
        display: none;
        width: auto;
        height: auto;
        background: none repeat scroll 0 0 white;
        border: 0 none;
        border-radius: 8px 8px 8px 8px;
        box-shadow: -3px 3px 15px #888888;
        color: black;
        font: 12px sans-serif;
        padding: 5px;
        text-align: center;
    }

    text {
        font: 10px sans-serif;
        color: white;
    }
    text.value {
        font-size: 100%;
        fill: white;
    }

    .axisHorizontal path{
        fill: none;
    }

    .axisHorizontal .tick line {
        stroke-width: 1;
        stroke: rgba(0, 0, 0, 0.2);
    }

    .bar {
        fill: steelblue;
        fill-opacity: .9;
    }
<script src="https://d3js.org/d3.v3.min.js"></script>

要了解有关d3嵌套的更多信息,请参见以下示例列表:http://bl.ocks.org/phoebebright/raw/3176159/

希望这会有所帮助。