D3.js饼图:如何根据我自己的分类自动创建和分配渐变的颜色比例

时间:2016-01-30 21:19:34

标签: d3.js colors pie-chart

我希望标题不会太混乱,但我很难以明确的方式制定这个问题。无论如何我会试一试。首先, 这是my pie chart,这是我的数据:

DATA.CSV
voce;categoria;val2015
amministrazione;funzioni;404571081
sociale;funzioni;235251679
territorio e ambiente;funzioni;286164667
viabilità e trasporti;funzioni;144185664
istruzione;funzioni;168774925
cultura;funzioni;55868045
sport;funzioni;27219432
turismo;funzioni;9544845
sviluppo economico;funzioni;14790363
servizi produttivi;funzioni;4334
polizia locale;funzioni;99007202
giustizia;funzioni;12147068
anticipazioni di cassa;rimborso prestiti;304323808
finanziamenti a breve termine;rimborso prestiti;0
prestiti obbligazionari;rimborso prestiti;38842996
quota capitale di debiti pluriennali;rimborso prestiti;0
quota capitale di mutui e prestiti;rimborso prestiti;128508755
spese per conto terzi;altro;232661261
disavanzo di amministrazione;altro;0

该图表应显示政府如何将预算分配给不同的职能部门。每个数据点的特点是:

  1. “voce”:预算的一部分分配的功能
  2. “categoria”:每项费用的宏观类别。其中有三个:“funzioni”; “rimborso prestiti”;和“altro”
  3. “val2015”:2015年分配给该职能的资金的绝对值
  4. 在我的可视化中,我在彼此之上创建了两个馅饼。 innerPie将预算划分为三个宏类别。 outerPie将它划分为19个不同的函数。

    我想为每个宏类别分配一种颜色(分别是绿色,红色和蓝色)。然后我想让类别的所有功能都以渐变的宏观类别颜色着色。

    例如,如果“funzioni”变为绿色,那么我希望属于该类别的12个函数逐渐变为从浅绿色到深绿色。

    首先,我想我会手动分配颜色。但是,我找不到能够提供给定颜色的十二种色调的颜色酿造器。

    然后我想我会替换颜色。如果macro-category1为绿色,则function1将为浅绿色,function2为深绿色,function3为浅绿色等等。但是某些函数的绝对值为0(即该年度没有为该函数分配预算) )。由于它们不会出现在饼图中,因此相同颜色的两个函数可能会彼此相邻。这是代码:

    var color = d3.scale.ordinal()
                .domain(["amministrazione", "sociale", "territorio e ambiente", "viabilità e trasporti", "istruzione", "cultura", "sport", "turismo", "sviluppo economico", "servizi produttivi", "polizia locale", "giustizia", "anticipazioni di cassa", "finanziamenti a breve termine", "prestiti obbligazionari", "quota capitale di debiti pluriennali;", "quota capitale di mutui e prestiti", "spese per conto terzi", "disavanzo di amministrazione"])
                .range(["rgb(116,196,118)", "rgb(35,139,69)", "rgb(116,196,118)", "rgb(35,139,69)", "rgb(116,196,118)", "rgb(35,139,69)", "rgb(116,196,118)", "rgb(35,139,69)", "rgb(116,196,118)", "rgb(35,139,69)", "rgb(116,196,118)", "rgb(35,139,69)", "rgb(251,106,74)", "rgb(103,0,13)", "rgb(251,106,74)", "rgb(103,0,13)", "rgb(251,106,74)", "rgb(116,196,118)", "rgb(0,68,27)"]);
    
    var colorInner = d3.scale.ordinal()
                .domain(["funzioni", "rimborso prestiti", "altro"])
                .range(["rgb(0,68,27)", "rgb(203,24,29)" , "rgb(33,113,181)"]); 
    

    解决方案是为每个宏类别使用三个阴影。这样可以解决问题,但我正在寻找更灵活的解决方案。

    由于我计划在数据集中添加更多年份,我该如何创建一个函数:

    1. 将宏类别的颜色作为输入
    2. 计算该类别中大于0的函数数量
    3. 为函数
    4. 指定x种颜色

      ----- ----- EDIT

      现在我创建了一个色标,我需要根据类别(对于宏色)和它的索引(对于宏色的阴影)为每个路径指定颜色。 我尝试了两件事,但都没有效果。

      var greenRange = ["rgb(199,233,192)", "rgb(0,68,27)"];
      var redRange = ["rgb(252,187,161)", "rgb(103,0,13)"];
      var blueRange = ["rgb(198,219,239)", "rgb(8,48,107)"];
      

      选项1

      function draw () {
      
      //(1) count the number of data points with value > in each category
      var countFunzioni=0;
      dataset.forEach (function (d) {if (d.categoria=="funzioni" && d.val2015>0) { countFunzioni += 1;}})
      
      var countRimborso=0;
      dataset.forEach (function (d) {if (d.categoria=="rimborso prestiti" && d.val2015>0) { countRimborso += 1;}})
      
      var countAltro=0;
      dataset.forEach (function (d) {if (d.categoria=="altro" && d.val2015>0) { countAltro += 1;}})
      
      //(2) create a color method for each category based on a the count calculated above and the range I determined
      var colorFunzioni = d3.scale.linear()
               .domain([0, countFunzioni])
               .range(redRange);
      
      var colorRimborso = d3.scale.linear()
               .domain([0, countRimborso])
               .range(redRange); 
      
      var colorAltro = d3.scale.linear()
               .domain([0, countAltro])
               .range(blueRange);
      
      //draw the chart
      chart = d3.select("#visualizationInner")
            .append("svg")
            .attr("id", "visualization")
            .attr("width", w)
            .attr("height", h)
            .append("g")
            .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
      
      //draw and color the paths
      var path = chart.datum(dataset).selectAll("path")
                  .data(pie)
                  .enter()
                  .append("path")
                  //(3) return the appropriate color method depending on the datum's category
                  .attr("fill", function(d, i) {
                    if (d.categoria=="funzioni") {return colorFunzioni(i);}
                    else if (d.categoria=="rimborso prestiti") {return colorRimborso(i);}
                    else if (d.categoria=="altro") {return colorAltro(i);}
                  })
                  .style("fill-opacity", 0.75)
                  .attr("d", arc);
      }
      

      选项2

      function draw () {
      
      //(1) same as above
      
      //(2) create a color method that adapts to each category's count and range
        var color = d3.scale.linear()
              .domain([0, function (d) {
                if (d.categoria=="funzioni") {return countFunzioni;}
                else if (d.categoria=="rimborso prestiti") {return countRimborso;}
                else if (d.categoria=="altro") {return countAltro;}
              }])
              .range(function (d) {
                if (d.categoria=="funzioni") {return greenRange;}
                else if (d.categoria=="rimborso prestiti") {return redRange;}
                else if (d.categoria=="altro") {return blueRange;}
              });
      
      ////(3) return the appropriate color method depending on the datum's category
              .attr("fill", function(d, i) {return color(i);}
      

      }

1 个答案:

答案 0 :(得分:1)

选择一种颜色并选择浅色和深色调,这将成为您的范围。然后,您的域名为[0, N]种颜色。例如,对于绿色,我们可以这样做:



var N = 12;
var greenRange = ['#cce0cc', '#001e00'];
      
var color = d3.scale.linear()
  .domain([0, N])
  .range(greenRange);
       
  d3.select('body')
    .append('div')
    .selectAll('.color')
    .data(d3.range(N))
    .enter()
    .append('div')
    .attr('class', 'color')
    .style('height', '50px')
    .style('width', '50px')
    .style('background-color', function(d,i){
      return color(i);
  })

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
&#13;
&#13;
&#13;

使用不同的N重新运行它,以了解它是如何产生颜色的。

<强> EDITS

我认为选项1 不起作用,因为当您致电return colorFunzioni(i);(或其他人)时,i将超出范围。你真正需要的是每种颜色的索引。这是一个快速重构:

var countFunzioni = 0,
    countRimborso = 0,
    countAltro = 0;
dataset.forEach(function(d){
    if (d.categoria=="funzioni" && d.val2015>0){
        d.colorIdx = countFunzioni;            
        countFunzioni += 1;
    } else if (d.categoria=="rimborso prestiti" && d.val2015>0){
        d.colorIdx = countRimborso;
        countRimborso += 1;
    } else if (d.categoria=="altro" && d.val2015>0) {
        d.colorIdx = countAltro;
        countAltro += 1;
    }
});

var colors = {};
colors.funzioni = d3.scale.linear()
    .domain([0, countFunzioni])
    .range(redRange);

colors.rimborso = d3.scale.linear()
    .domain([0, countRimborso])
    .range(redRange); 

colors.altro = d3.scale.linear()
    .domain([0, countAltro])
    .range(blueRange);

随后:

...
.attr("fill", function(d, i) {
    return colors[d.categoria](d.colorIdx); 
});