Vahe
Vahe

Reputation: 1841

NVD3.js - How to add bar text to each bar in a stacked graph?

I have created a multi bar chart in NVD3/AngularJS. I want to display text inside each rectangular bar along with its value as seen in the JSON below.

How do I display text values to the graph within each bar?

NVD3 Chart Definition

multiBarChart: {
        options: function(){
          return {
            chart: {
              type: 'multiBarChart',
              stacked: true,
              x: function(d){return d.x;},
              y: function(d){return d.y;},
              text: function(d){return d.x;},
              showLabels: true,
              showLegend: false,
              transitionDuration: 500,
              forceX: ["Team", "Meeting", "Phase", "Source"],
              xAxis: {
                axisLabel: 'Category',
                axisLabelDistance: -8
              },
              yAxis: {
                axisLabel: 'Number Of Action Items',
              }
            }
          }
        },
        data: categoryChartData
      }

JSON Data (categoryChartData)

  [ 
                                {"values" : [
                                    {
                                        "y" :10,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Team1"
                                },

                                {"values" : [
                                    {
                                        "y" :5,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Team2"
                                },
                                    {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 7,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Meeting1"
                                },
                                    {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 3,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Meeting2"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :9,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Phase1"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :5,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 0,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Phase1"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 2,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Internal"
                                },
                                {"values" : [
                                    {
                                        "y" :0,
                                        "x" : "Team"
                                    }, {
                                        "y" : 0,
                                        "x" : "Meeting"
                                    },
                                    {
                                        "y" :0,
                                        "x" : "Phase"
                                    }, {
                                        "y" : 1,
                                        "x" : "Source"
                                    }
                                    ],
                                    "key" : "Customer"
                                }


                                ];

Category Stacked Chart

Upvotes: 2

Views: 4033

Answers (2)

Bennett Adams
Bennett Adams

Reputation: 1818

Angular-nvd3 doesn't do this natively for multi-bar charts, due to some complications from animating stacked bars, but it will for discrete bar charts, as How to display values in Stacked Multi-bar chart - nvd3 Graphs explored. However, in an update to his answer to that question, @Topicus linked to a gist they wrote that accomplishes what you're looking for.

I adapted the gist to your situation; you can see the result in this Plunker. You can play with the formatting a little if the labels show up a little wonky. The key is that the labels need to be appended after the animation is complete, so I set a timeout equal to (could also be a little greater than) the value of the transitionDuration chart property. I also removed all zero values so they don't obscure the nonzero ones.

$scope.options = {
  chart: {
    type: 'multiBarChart',
    height: 500,
    transitionDuration: 500,
    ...
  }
};

$scope.data...

$timeout(function () {
  d3.selectAll('.nv-multibar .nv-group').each(function(group){
    var g = d3.select(this);
  
    // Remove previous labels if there is any
    g.selectAll('text').remove(); 
    g.selectAll('.nv-bar').each(function(bar) {
      var b = d3.select(this);
      var barWidth = b.attr('width');
      var barHeight = b.attr('height');

      g.append('text')
        // Transforms shift the origin point then the x and y of the bar
        // is altered by this transform. In order to align the labels
        // we need to apply this transform to those.
        .attr('transform', b.attr('transform'))
        .text(function() {
          // No decimals format and eliminate zero values
          if (bar.y === 0) {
            return;
          }
          return parseFloat(bar.y).toFixed(0);
        })
        .attr('y', function() {
          // Center label vertically
          var height = this.getBBox().height;
          return parseFloat(b.attr('y')) + 15; // 15 is the label's margin from the top of bar
        })
        .attr('x', function() {
          // Center label horizontally
          var width = this.getBBox().width;
          return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
        })
        .style("stroke","black")
        .attr('class', 'bar-values');
    });
  });
}, 500);

Upvotes: 5

吴张明
吴张明

Reputation: 379

I think the answer have two points to add. 1. we add the code add the value text in the callback function.like:

callback: function(chart){
    chart.dispatch.on('stateChange', function(e){
        setMultiBarValue(e.stacked);
    });

    setMultiBarValue(config.stacked);
}

2.add function to show right text in the group/stacked option

function setMultiBarValue(chart, config, dataRange, stacked, time){
    if(config.type === 'multiBarChart'){
        if(stacked === true){
            //stack set your totalMin, totalMax to make all the value visible.
            chart.yDomain([dataRange.totalMin, dataRange.totalMax]);
            initStackLables(d3.select(chart.container), time || 1000);
        }else{
            //group: set your min,max to make all the value visible.
            chart.yDomain([dataRange.yMin, dataRange.yMax]);
            initGroupLabels(d3.select(chart.container), time || 1000);
        }
    }
}
  1. define the tow function initStackLables, initGroupLabels,like:

    1).initGroupLabels

    var initGroupLabels = function(container, time) { time = time || 500; container.selectAll('.nv-multibar .nv-group').each(function(group) { var g = d3.select(this); // Remove previous labels if there is any g.selectAll('text').remove(); }); $timeout(function() { container.selectAll('.nv-multibar .nv-group').each(function(group) { var g = d3.select(this);

                g.selectAll('.nv-bar').each(function(bar, index) {
                    var b = d3.select(this);
                    var barWidth = b.attr('width');
                    var barHeight = b.attr('height');
    
                    g.append('text')
                    // Transforms shift the origin point then the x and y of the bar
                    // is altered by this transform. In order to align the labels
                    // we need to apply this transform to those.
                    .attr('transform', b.attr('transform')).text(function() {
                        // No decimals format and eliminate zero values
                        if (bar.y === 0) {
                            return;
                        }
                        return parseFloat(bar.y);
                    }).attr('y',
                    function() {
                        // Center label vertically
                        var height = this.getBBox().height;
                        return parseFloat(b.attr('y')) - 10; // 10 is the label's margin from the top of bar
                    }).attr('x',
                    function() {
                        // Center label horizontally
                        var width = this.getBBox().width;
                        return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
                    }).style('stroke', 'black').attr('class', 'bar-values');
                });
            });
        },
        time);
    }
    

    2)initStackLables

    var initStackLables =function(container, time){ time = time || 500;

    container.selectAll('.nv-multibar .nv-group').each(function(group){
        var g = d3.select(this);
        // Remove previous labels if there is any
        g.selectAll('text').remove(); 
    });
    $timeout(function () {
        var length = container.selectAll('.nv-multibar .nv-group').length;
        var vArr = []; var yArr = [];
        container.selectAll('.nv-multibar .nv-group').each(function(group){
            var g = d3.select(this);
            g.selectAll('.nv-bar').each(function(bar, index){
                var b = d3.select(this); var by = parseFloat(b.attr('y'));
                var barHeight = b.attr('y');
                vArr[index] = vArr[index] || 0;
                vArr[index] += parseFloat(bar.y) || 0;
                yArr[index] = yArr[index] || by;
                yArr[index] = yArr[index] > by ? by : yArr[index];
            });
        });
        container.selectAll('.nv-multibar .nv-group').each(function(group, index){
            if(index === 0){
                var g = d3.select(this);
                // Remove previous labels if there is any
                g.selectAll('text').remove(); 
                g.selectAll('.nv-bar').each(function(bar, index){
                    var b = d3.select(this);
                    var barWidth = b.attr('width');
                    var barHeight = b.attr('height');
    
                    g.append('text')
                        .attr('transform', b.attr('transform'))
                        .text(function(){
                            if (bar.y === 0) {
                                return;
                            }
                            return parseFloat(vArr[index];
                        })
                        .attr('y', function(){
                            var height = this.getBBox().height;
                            return parseFloat(yArr[index]) - 10; // 10 is the label's margin from the top of bar
                        })
                        .attr('x', function(){
                            var width = this.getBBox().width;
                            return parseFloat(b.attr('x')) + (parseFloat(barWidth) / 2) - (width / 2);
                        })
                        .style('stroke','black')
                        .attr('class', 'bar-values');
                });
            }
        });
    
    }, time);
    

    }

Upvotes: 0

Related Questions