0

I'm creating a visualisation using a dynamic bubblechart. I have it working however instead of having floating tooltips I'd like to just label each of the bubbles with its name, I've tried a number of different approaches but can't seem to get it working. Any tips would be appreciated!

window.custom_bubble_chart = (function(d3, CustomTooltip) {
 //"use strict";


     $("#tags").html("");

// Work out chart sizes
var width = $("#tags").width();
var height = $("#tags").height();

 var tooltip = CustomTooltip("gates_tooltip", 180);
 var layout_gravity = -0.01;
 var damper = 0.1;
 var nodes = [];
 var vis, force, circles, radius_scale;

  var center = {x: width / 2, y: height / 2};

 var year_centers = {
  "positive": {x: width / 3, y: height / 2},
  "neutral": {x: width / 2, y: height / 2},
  "negative": {x: 2 * width / 3, y: height / 2}
   };

   var fill_color = d3.scale.ordinal()
              .domain(["low", "medium", "high"])
              .range(["#99cc00", "#ff4444", "#33b5e5"]);

 function custom_chart(data) {


var max_amount = d3.max(data, function(d) { return parseInt(d.freq, 10); } );
radius_scale = d3.scale.pow().exponent(0.5).domain([0, max_amount]).range([2, 25]);

//create node objects from original data
//that will serve as the data behind each
//bubble in the vis, then add each node
//to nodes to be used later
data.forEach(function(d){
  var node = {
    id: d.id,
    radius: radius_scale(parseInt(d.freq, 4)),
    value: d.freq,
    name: d.word,
    group: d.sentiment_adj,
    year: d.sentiment_adj,
    x: Math.random() * 900,
    y: Math.random() * 800
  };
  nodes.push(node);
});

nodes.sort(function(a, b) {return b.value- a.value; });

vis = d3.select("#tags").append("svg")
            .attr("width", width)
            .attr("height", height)
            .attr("id", "svg_tags");

circles = vis.selectAll("circle")
             .data(nodes, function(d) { return d.id ;});

circles.enter().append("circle")
  .attr("r", 0)
  .attr("fill", function(d) { return fill_color(d.group) ;})
  .attr("stroke-width", 2)
  .attr("stroke", function(d) {return d3.rgb(fill_color(d.group)).darker();})
  .attr("id", function(d) { return  "bubble_" + d.id; })
  .on("mouseover", function(d, i) {show_details(d, i, this);} )
  .on("mouseout", function(d, i) {hide_details(d, i, this);} );

  //fill circles with text - testing code that doesnt work!
//circles.append("text")
  //.attr("text-anchor", "middle")
 // .attr("dy", ".3em")
 // .text(function(d) { return data.name ; });

circles.transition().duration(2000).attr("r", function(d) { return d.radius; });

 }

 function charge(d) {
return -Math.pow(d.radius, 2.0) / 8;
 }

  function start() {
   force = d3.layout.force()
        .nodes(nodes)
        .size([width, height]);
 }

 function display_group_all() {
  force.gravity(layout_gravity)
     .charge(charge)
     .friction(0.9)
     .on("tick", function(e) {
        circles.each(move_towards_center(e.alpha))
               .attr("cx", function(d) {return d.x;})
               .attr("cy", function(d) {return d.y;});
       });
   force.start();
   hide_years();
 }

 function move_towards_center(alpha) {
   return function(d) {
    d.x = d.x + (center.x - d.x) * (damper + 0.02) * alpha;
     d.y = d.y + (center.y - d.y) * (damper + 0.02) * alpha;
  };
 }

  function display_by_year() {
    force.gravity(layout_gravity)
     .charge(charge)
     .friction(0.9)
    .on("tick", function(e) {
      circles.each(move_towards_year(e.alpha))
             .attr("cx", function(d) {return d.x;})
             .attr("cy", function(d) {return d.y;});
    });
   force.start();
  display_years();
}

  function move_towards_year(alpha) {
return function(d) {
  var target = year_centers[d.year];
  d.x = d.x + (target.x - d.x) * (damper + 0.02) * alpha * 1.1;
  d.y = d.y + (target.y - d.y) * (damper + 0.02) * alpha * 1.1;
   };
}


 function display_years() {
  var years_x = {"Positive": width/3, "Neutral": width / 2, "Negative": width - width/3};
  var years_data = d3.keys(years_x);
  var years = vis.selectAll(".years")
             .data(years_data);

  years.enter().append("text")
               .attr("class", "years")
               .attr("x", function(d) { return years_x[d]; }  )
               .attr("y", 40)
               .attr("text-anchor", "middle")
               .text(function(d) { return d;});

}

function hide_years() {
    var years = vis.selectAll(".years").remove();
 }


 function show_details(data, i, element) {
d3.select(element).attr("stroke", "black");
var content = "<span><b> " + data.name + "</b></span><br/>";
    tooltip.showTooltip(content, d3.event);
}

 function hide_details(data, i, element) {
  d3.select(element).attr("stroke", function(d) { return         d3.rgb(fill_color(d.group)).darker();} );
tooltip.hideTooltip();
 }

  var my_mod = {};
 my_mod.init = function (_data) {
custom_chart(_data);
start();
};

my_mod.display_all = display_group_all;
my_mod.display_year = display_by_year;
my_mod.toggle_view = function(view_type) {
if (view_type == 'year') {
  display_by_year();
} else {
  display_group_all();
  }
};

return my_mod;
 })(d3, CustomTooltip);
alto125
  • 19
  • 6
  • You cannot append text elements to circle elements since circle elements are not containers. You will need to create a group element ("g) and append circles and associated text elements to it. – FernOfTheAndes Feb 13 '14 at 00:35

1 Answers1

0

You can't add text within a shape in SVG. The text elements need to be positioned separately.

You have two options:

  • create a selection of <text> elements, and join the data to them, completely separate from the circles; or,
  • make your main selection, to which you join the data, consist of <g> elements, then add both the circle and the text to the group.

The second option makes updating easier, although you will have to change your update function to use transforms for positioning instead of cx and cy. Here's a tree layout that uses groups for each node, containing a circle and a label each.

AmeliaBR
  • 27,344
  • 6
  • 86
  • 119