不对数据进行排序时金字塔无法正确呈现

时间:2018-07-18 03:04:38

标签: javascript d3.js

嗨,我已经使用d3js搜索了金字塔图,但是没有找到任何不对数据进行排序即可呈现金字塔图的示例。我正在尝试通过删除代码的排序部分来适应this pyramid图表示例。

这就是我所拥有的(fiddle form):。

d3.pyramid = function() {
  var size = [1,1],
      value = function(d) { return d.value},
      coordinates;
  
  var percentageValues = function (data) {
    var values = data.map(value);
    var sum = d3.sum(values, function (d){
      return +d;
    });
    var percentValues = data.map(function (d,i){
      d.value = +values[i];
      return values[i]/sum*100;
    });
    
    //I don't want sorting, i want to display in the same order data is passwed, i pass high-medium-low
    //like in high chart https://jsfiddle.net/nc7bzdx3/7/
   /*  percentValues.sort(function(a,b){
      return b-a;
    }); */
    
    
    return percentValues;
  }
  var coordinatesCalculation = function(data){
    var w = size[0],
        h = size[1],
        ratio = (w/2)/h,
        percentValues = percentageValues(data),
        coordinates = [],
        area_of_triangle = (w * h) / 2;
    function d3Sum (i) {
      return d3.sum(percentValues,function (d, j){
        if (j>=i) {
          return d;
        }
      });
    }
    for (var i=0,len=data.length;i<len; i++){
      var selectedPercentValues = d3Sum(i),
          area_of_element = selectedPercentValues/100 * area_of_triangle,
          height1 = Math.sqrt(area_of_element/ratio),
          base = 2 * ratio * height1,
          xwidth = (w-base)/2;
      if (i===0){
        coordinates[i] = {"values":[{"x":w/2,"y":0},{"x":xwidth,"y":height1},{"x":base+xwidth,"y":height1}]};
      }else{
        coordinates[i] = {"values":[coordinates[i-1].values[1],{"x":xwidth,"y":height1},{"x":base+xwidth,"y":height1},coordinates[i-1].values[2]]};
      }

    }
    coordinates[0].values[1] = coordinates[coordinates.length-1].values[1];
    coordinates[0].values[2] = coordinates[coordinates.length-1].values[2];
    var first_data = coordinates.splice(0,1);
    coordinates = coordinates.reverse();
    coordinates.splice(0,0,first_data[0]);
    return coordinates;
  } 
  function pyramid(data) {
    var i = 0,
        coordinates = coordinatesCalculation(data);
    
  /*   data.sort(function(a,b) {
      return a.value - b.value;
    }) */
    
    data.forEach(function(){
      data[i].coordinates = coordinates[i].values;
      i++;
    })
    return data;
  }
  pyramid.size = function(s){
    if(s.length === 2) {
      size = s;                    
    }
    return pyramid;
  }
  pyramid.value = function(v) {
    if (!arguments.length) return value;
    value = v;
    return pyramid;
  };
  return pyramid;
}



var data = [
        {priority: 'High', count: 1000, key: 1},
        {priority: 'Medium', count: 120, key: 2},
        {priority: 'Low', count: 60, key: 3}
    ];
    
    var svg;
    var CANVAS_CLASS = "canvas";
    var MARGIN = {top: 20, right: 40, bottom: 30, left: 40};

    var width = 400, height = 300;

    var color = d3.scale.ordinal()
            .range(["#F24936", "#F6BF18", "#FFFFFF", "#0000FF"]);


    var svg = d3.select("body").append('svg')
                .attr("width", width + 300)
                .attr("height", height)
                .attr('class', CANVAS_CLASS)
                .append("g");


    var pyramid = d3.pyramid()
            .size([width, height])
            .value(function (d) {
                return d.count;
            });

    var line = d3.svg.line()
            .interpolate('linear-closed')
            .x(function (d, i) {
                return d.x;
            })
            .y(function (d, i) {
                return d.y;
            });
            
    var pyramidData = pyramid(data);

    var g = svg.selectAll(".pyramid-group")
            .data(pyramidData)
            .enter().append("g")
            .attr("class", "pyramid-group");

    g.append("path")
            .attr("d", function (d) {
                return line(d.coordinates);
            })
            .style("fill", function (d) {
                return color(d.priority);
            });

    g.append("text")
            .attr({
                "y": function (d, i) {
                    if (d.coordinates.length === 4) {
                        return (((d.coordinates[0].y - d.coordinates[1].y) / 2) + d.coordinates[1].y) + 5;
                    } else {
                        return (d.coordinates[0].y + d.coordinates[1].y) / 2 + 10;
                    }
                },
                "x": function (d, i) {
                    return width / 2;
                }
            })
            .style("text-anchor", "middle")
            .text(function (d) {
                return d.priority+ '_'+d.count;
            });
* {
  margin: 0;
  padding: 0;
  border: 0;
}

body {
  background: #ffd;
}

 .arc path {
                stroke: #fff;
            }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.10/d3.min.js"></script>

我已注释掉排序,但是输出不正确:区域不对应于未排序的值。如何使金字塔形图按输入顺序显示输入数据的区域?

任何帮助将不胜感激。谢谢

1 个答案:

答案 0 :(得分:0)

如果我理解正确,则不会为每个分段呈现正确的区域。如果我们看一下原始代码,则有两种倒置类型b-aa-b,它们都基于value属性。似乎按百分比排序时,排序与按值排序数据时相反。通过删除所有排序,我们没有基准和百分比相反的顺序。

因此,如果我们反转百分比的顺序,则应该使基准面与面积正确对齐:

d3.pyramid = function() {
  var size = [1,1],
      value = function(d) { return d.value},
      coordinates;
  
  var percentageValues = function (data) {
    var values = data.map(value);
    var sum = d3.sum(values, function (d){
      return +d;
    });
    var percentValues = data.map(function (d,i){
      d.value = +values[i];
      return values[i]/sum*100;
    });

    percentValues.reverse();
    
    
    return percentValues;
  }
  var coordinatesCalculation = function(data){
    var w = size[0],
        h = size[1],
        ratio = (w/2)/h,
        percentValues = percentageValues(data),
        coordinates = [],
        area_of_triangle = (w * h) / 2;
    function d3Sum (i) {
      return d3.sum(percentValues,function (d, j){
        if (j>=i) {
          return d;
        }
      });
    }
    for (var i=0,len=data.length;i<len; i++){
      var selectedPercentValues = d3Sum(i),
          area_of_element = selectedPercentValues/100 * area_of_triangle,
          height1 = Math.sqrt(area_of_element/ratio),
          base = 2 * ratio * height1,
          xwidth = (w-base)/2;
      if (i===0){
        coordinates[i] = {"values":[{"x":w/2,"y":0},{"x":xwidth,"y":height1},{"x":base+xwidth,"y":height1}]};
      }else{
        coordinates[i] = {"values":[coordinates[i-1].values[1],{"x":xwidth,"y":height1},{"x":base+xwidth,"y":height1},coordinates[i-1].values[2]]};
      }

    }
    coordinates[0].values[1] = coordinates[coordinates.length-1].values[1];
    coordinates[0].values[2] = coordinates[coordinates.length-1].values[2];
    var first_data = coordinates.splice(0,1);
    coordinates = coordinates.reverse();
    coordinates.splice(0,0,first_data[0]);
    return coordinates;
  } 
  function pyramid(data) {
    var i = 0,
        coordinates = coordinatesCalculation(data);
    
  /*   data.sort(function(a,b) {
      return a.value - b.value;
    }) */
    
    data.forEach(function(){
      data[i].coordinates = coordinates[i].values;
      i++;
    })
    return data;
  }
  pyramid.size = function(s){
    if(s.length === 2) {
      size = s;                    
    }
    return pyramid;
  }
  pyramid.value = function(v) {
    if (!arguments.length) return value;
    value = v;
    return pyramid;
  };
  return pyramid;
}



var data = [
        {priority: 'High', count: 1000, key: 1},
        {priority: 'Medium', count: 500, key: 2},
        {priority: 'Low', count: 160, key: 3}
    ];
    
    var svg;
    var CANVAS_CLASS = "canvas";
    var MARGIN = {top: 20, right: 40, bottom: 30, left: 40};
    var width = 400, height = 150;

    var color = d3.scale.ordinal()
            .range(["#F24936", "#F6BF18", "#FFFFFF", "#0000FF"]);


    var svg = d3.select("body").append('svg')
                .attr("width", width + 300)
                .attr("height", height)
                .attr('class', CANVAS_CLASS)
                .append("g");


    var pyramid = d3.pyramid()
            .size([width, height])
            .value(function (d) {
                return d.count;
            });

    var line = d3.svg.line()
            .interpolate('linear-closed')
            .x(function (d, i) {
                return d.x;
            })
            .y(function (d, i) {
                return d.y;
            });
            
    var pyramidData = pyramid(data);

    var g = svg.selectAll(".pyramid-group")
            .data(pyramidData)
            .enter().append("g")
            .attr("class", "pyramid-group");

    g.append("path")
            .attr("d", function (d) {
                return line(d.coordinates);
            })
            .style("fill", function (d) {
                return color(d.priority);
            });

    g.append("text")
            .attr({
                "y": function (d, i) {
                    if (d.coordinates.length === 4) {
                        return (((d.coordinates[0].y - d.coordinates[1].y) / 2) + d.coordinates[1].y) + 5;
                    } else {
                        return (d.coordinates[0].y + d.coordinates[1].y) / 2 + 10;
                    }
                },
                "x": function (d, i) {
                    return width / 2;
                }
            })
            .style("text-anchor", "middle")
            .text(function (d) {
                return d.priority+ '_'+d.count;
            });
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>