1

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;
        }
});
EGHM
  • 2,144
  • 23
  • 37
Tim Sparks
  • 13
  • 6

2 Answers2

1

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!

Cyril Cherian
  • 32,177
  • 7
  • 46
  • 55
  • 1
    This is fantastic, thanks for that! :D (I can't make the edit because it's too small, but for future viewers it'd probably be helpful to fix the syntax on the last comment in the quoted code here!) – Tim Sparks Dec 15 '15 at 22:54
0

You need array for names that you want to give. Check this code to cross check:

 for (var i = 0; i < groups; i++) {
                  var names = new Array ('London', 'Paris','New York','India');
                    data.push({
                        key: names[i],
                        values: []
                    });

Code in App.js (edited) :

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++) {
              var names = new Array ('London', 'Paris','New York','India');
                data.push({
                    key: names[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;
        }
});