nvd3.jsangular-nvd3

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


Solution

  • 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);