Search code examples
angularjsd3.jsnvd3.jsangular-nvd3

Appending text to points in angular-nvd3


I'm currently redesigning some visualizations to go from static embedded output from R to interactive graphs using angular-nvd3. I've made considerable progress and have nearly finished re-implementing all the options necessary.

However, the last part that is evading me is figuring out how to add persistent labels to all the data points.

This example of the old static output hopefully makes it clear what I mean.

While I have customized tooltips for this, it was one of the client requests to have names display as a toggle, so I don't think I can get around it.

Is there a built-in way to do this? I couldn't find anything through the nvd3 documentation.

I've included code from the reference scatter plot example - mine is very specific so this would be easier to work from.

var app = angular.module('plunker', ['nvd3']);

app.controller('MainCtrl', function($scope) {
 $scope.options = {
            chart: {
                type: 'scatterChart',
                height: 450,
                color: d3.scale.category10().range(),
                scatter: {
                    onlyCircles: false
                },
                showDistX: true,
                showDistY: true,
                tooltipContent: function(key) {
                    return '<h3>' + key + '</h3>';
                },
                duration: 350,
                xAxis: {
                    axisLabel: 'X Axis',
                    tickFormat: function(d){
                        return d3.format('.02f')(d);
                    }
                },
                yAxis: {
                    axisLabel: 'Y Axis',
                    tickFormat: function(d){
                        return d3.format('.02f')(d);
                    },
                    axisLabelDistance: -5
                },
                zoom: {
                    //NOTE: All attributes below are optional
                    enabled: false,
                    scaleExtent: [1, 10],
                    useFixedDomain: false,
                    useNiceScale: false,
                    horizontalOff: false,
                    verticalOff: false,
                    unzoomEventType: 'dblclick.zoom'
                }
            }
        };

        $scope.data = generateData(4,40);

        /* Random Data Generator (took from nvd3.org) */
        function generateData(groups, points) {
            var data = [],
                shapes = ['circle', 'cross', 'triangle-up', 'triangle-down', 'diamond', 'square'],
                random = d3.random.normal();

            for (var i = 0; i < groups; i++) {
                data.push({
                    key: 'Group ' + i,
                    values: []
                });

                for (var j = 0; j < points; j++) {
                    data[i].values.push({
                        x: random()
                        , y: random()
                        , size: Math.random()
                        , shape: shapes[j % 6]
                    });
                }
            }
            return data;
        }
});

Solution

  • No nvd3 has nothing to show labels as per your requirement.

    But this can be achieved mixing a little of d3 like this:

      $scope.clear= function(){
        d3.selectAll(".label").remove();//will clear all the labels
      }
      $scope.showLabel= function(){
        $scope.clear();
        //for each path make label
        d3.selectAll(".nv-group path")[0].forEach(function(d){
              var tf = d3.select(d).attr("transform")
              t = d3.transform(tf).translate;
              t[0] = t[0] +10;//moving the translate x by 5 pixel.
              console.log(d3.select(d).data()[0])//data associated with the point
              d3.select(d.parentNode)
                .append("text")
                .attr("class", "label")
                .text("data: "+ d3.select(d).data()[0][1])//putting data
                .attr("transform", "translate("+t[0]+","+t[1]+")");/setting the changed translate for label
    
        });
    
      }
    

    Working code here

    Hope this helps!