Overlap in d3 wordcloud

d3 word cloud v5
ember word cloud
threejs word cloud
word cloud algorithm
word cloud plugin
word cloud generator api
javascript svg word cloud
word cloud api

I use Jason Davies' wordcloud library for d3 (https://github.com/jasondavies/d3-cloud) and my problem is that the words in the cloud overlap.

I am aware that there are already questions regarding this issue on stack overflow (and other sites), but none of these helped in my case.

In the following example I use the example cloud from Jason Davies' site and altered only a few things:

  • I read my words and their sizes from an external file.
  • I set rotation to 0. Rotation angle does not seem to make a difference though.
  • I commented out the "Impact" font, to rule out any issues with loading the font. (It makes no difference either though.)

Here is my code:

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="d3.js"></script>
<script src="d3.layout.cloud.js"></script>
<script>
   d3.tsv("testdata.txt", 
  function(error, data) {

  var fill = d3.scale.category20();



  d3.layout.cloud().size([300, 300])
      .words(data)
      .padding(1)
      .rotate(function(d) { return 0; })
  //    .font("Impact")
      .fontSize(function(d) { return d.size; })
      .on("end", draw)
      .start();

  function draw(words) {
    d3.select("body").append("svg")
        .attr("width", 300)
        .attr("height", 300)
      .append("g")
        .attr("transform", "translate(150,150)")
      .selectAll("text")
        .data(words)
      .enter().append("text")
        .style("font-size", function(d) { return d.size + "px"; })
    //    .style("font-family", "Impact")
        .style("fill", function(d, i) { return fill(i); })
        .attr("text-anchor", "middle")
        .attr("transform", function(d) {
          return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
        })
        .text(function(d) { return d.word; });
  }
  }
  )

</script>

The testdata looks like this (the color information is not used in the example):

word    size    color
der 39  #a9a9a9
die 37  #a9a9a9
und 30  #a9a9a9
athenischen 29  #a9a9a9
Die 29  #a9a9a9
eine    28  #a9a9a9
,   27  #a9a9a9
einer   26  #a9a9a9
attischen   26  #a9a9a9
liberalen   26  #1e90ff
zur 25  #a9a9a9
athenische  24  #a9a9a9
christliche 23  #a9a9a9
attische    23  #a9a9a9
_START_ 22  #a9a9a9 
reinen  22  #a9a9a9
englischen  21  #a9a9a9 
oder    21  #a9a9a9
--  21  #a9a9a9
radikalen   21  #a9a9a9
Q*M 21  #a9a9a9
Q*M 21  #a9a9a9
christlichen    20  #a9a9a9
schöne  20  #1e90ff
repräsentativen 20  #a9a9a9
sozialen    20  #a9a9a9
hellenische 19  #1e90ff
modernen    19  #a9a9a9
radikale    19  #a9a9a9
griechische 19  #a9a9a9
-   18  #a9a9a9
schönen 18  #1e90ff
alle    18  #a9a9a9
radicalen   18  #a9a9a9
als 17  #a9a9a9
neuen   17  #a9a9a9
perikleischen   16  #a9a9a9
bürgerlichen    16  #a9a9a9
Namen   16  #1e90ff

If I run the js script with the test data my word cloud comes out with overlaps. Sometimes it only happens after a few reloads, but it is fairly frequent.

Other people reported the same issue and found that it was related to using web fonts or skipping the rotate parameter. This does not apply in my example.

I suspect that it might be related to the fact that there are to many words for the canvas size, however, I also did tests where I signficantly increased the canvas size and it still happened (though less frequently, as the random placement of the words made it less likely). In addition to that, you can see that several words are not shown at all due to the small canvas size. Why leave some out and create overlap for others? So I think the issue lies elsewhere.

Any ideas?

Thanks!

I ended up asking Jason Davies himself and it was actually a pretty simple mistake: You have to specify the text accessor function in the first statement (not only in the "draw" function). It works if you add one line like this:

d3.layout.cloud().size([300, 300])
  .words(data)
  .padding(1)
  .rotate(function(d) { return 0; })
//    .font("Impact")
  .text(function(d) { return d.word; }) // THE SOLUTION
  .fontSize(function(d) { return d.size; })
  .on("end", draw)
  .start();

Can't get the words to never overlap · Issue #15 · jasondavies/d3 , With the following, words almost always overlap: d3.layout.cloud().size([1000, 400]) .words(menuArray.map(function(d) { return {text: d.title,  Hello! I am aware that there is already a solved post on a very similar issue, but the solution described there does not apply in my case. When I try to use the wordcloud layout, I get frequent overlaps.

I have tried a sample for you to fiddle with, Please have a look. wordcloud without overlap

essentially:

<div id="cloud"></div> 

// First define your cloud data, using `text` and `size` properties:


var fill = d3.scale.category20();
var words = {
"Battery Related": "52382",
"Billing": "52412",
"Break Related": "52490",
"Chain Related": "52471",
"Clutch Related": "52468",
"Dealer attitude": "52488",
"Electrical Related": "52352",
"Engine Related": "52446",
"Handle Bar Related": "52486",
"Happy": "52472",
"Jerking": "52325",
"Jerking Problem": "52325",
"Low Mileage": "52489",
"Noise": "52462",
"Poor Pickup": "52406",
"Running Off": "52242",
"Service Quality": "52488",
"Silencer Problem": "52468",
"Starting Trouble": "52490",
"Suspension Related": "52365",
"Vehicle Noise": "52467",
"Vibration": "52463",
"Washing": "52488"
};
var max_freq = 52490;
var cloudwords = ["Battery Related", "Billing", "Break Related", "Chain Related", "Clutch Related", "Dealer attitude", "Electrical Related", "Engine Related", "Handle Bar Related", "Happy", "Jerking", "Jerking Problem", "Low Mileage", "Noise", "Poor Pickup", "Running Off", "Service Quality", "Silencer Problem", "Starting Trouble", "Suspension Related", "Vehicle Noise", "Vibration", "Washing"];
var url = 'http://xxx.yyyy.zz.ww/?q=abc/';
var width = 800,
height = 800;

var leaders = cloudwords
.map(function(d) {

return {
  text: d,
  size: 5 + (words[d] / max_freq) * 0.9 * 30 // *the size of the "box" occupied by each word. has no relation to text size.
};
})
 .sort(function(a, b) {
 return d3.descending(a.size, b.size)
});

var leaderScale = d3.scale.linear().range([1, 20]); // *scale range to plot the relative sizes of the words.

leaderScale.domain([d3.min(leaders, function(d) {
return d.size;
}),
d3.max(leaders, function(d) {
return d.size;
})
]);

 // Next you need to use the layout script to calculate the placement, rotation and size of each word:

 d3.layout.cloud().size([width, height])
.words(leaders)
.padding(0) //fiddle with padding here, does not really have any effect    on overlap.
.rotate(function() {
 return ~~0; //to keep the words horizontal 
 })
 .font("Impact")
 .fontSize(function(d) {
 return d.size;
 })
 .on("end", drawCloud)
 .start();

 function drawCloud(words) {
 d3.select("#cloud").append("svg")
 .attr("width", width)
 .attr("height", height)
 .attr("text-align", "center")
 .append("g")
 .attr("transform", "translate(" + [width >> 1, height >> 1] + ")")    //for transalting words to their different postions.
 .selectAll("text")
 .data(words)
 .enter().append("text")
 .style("font-size", function(d) {
  return leaderScale(d.size) + "px"; //used scale to resize words to a linear scale.
 })
 .style("font-family", "Impact")
 .style("fill", function(d, i) {
  return fill(i);
 })
 .attr("text-anchor", "middle")
 .attr("transform", function(d) {
  return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")";
 })
 .text(function(d) {
  return d.text;
 })
 .on("click", function(d, i) {
  window.open(url + d.text);
 });
 }

 // set the viewbox to content bounding box (zooming in on the content, effectively trimming whitespace)

 var svg = document.getElementsByTagName("svg")[0];
 var bbox = svg.getBBox();
 var viewBox = [bbox.x, bbox.y, bbox.width, bbox.height].join(" ");
 svg.setAttribute("viewBox", viewBox);

Overlap in wordcloud · Issue #38 · jasondavies/d3-cloud · GitHub, When I try to use the wordcloud layout, I get frequent overlaps. For a test case I used the example code from this page with some slight changes  This is the wordcloud section of the gallery. If you want to know more about this kind of chart, visit data-to-viz.com.If you're looking for a simple way to implement it in d3.js, pick an example below.

The fix by the author didn't work for me. What did work was to specify the .font() in the cloud layout setup and declare the same font-family in the draw code - so ironically, the bit that the author above has commented out. This gives the code the font to calculate dimensions from. Without it, it takes a best guess.

d3.layout.cloud().size([800, 400])
  .words(words)
  .font('Impact') // <-- what mattered
  .fontSize(d => d.size)
  .on('end', draw)
  .start()

You'll need to also specify the font-family in the draw() function so that the cloud renders the words in the correct font that matches what you declared above :

.attr('font-family', 'Impact')

Word cloud comparison - bl.ocks.org, it can lead to some overlapping (cf. around Good word),; it can produce some sparsed word cloud when many words disappear;. Cloud storm is  Size of the word correlates with the frequency of the word’s usage. when size increases, we get the problem of overlapping and the other words won’t be visible normally. for that we increased the transparency of words which are bigger, so that big words don’t hide the small words while overlapping. As Jason Davies, creator of d3 word cloud library himself, you have to specify the text accessor function in the first statement (not only in the “draw” function).

Visualising a wordcloud with D3 Javascript – Alagarasan mahalingam, Here we Use Jason Davies word cloud library to Main d3 functions d3.layout.​cloud().size([800, 300]) .words(frequency_list) .rotate(0) . which are bigger, so that big words don't hide the small words while overlapping. How the Word Cloud Generator Works The layout algorithm for positioning words without overlap is available on GitHub under an open source license as d3-cloud . Note that this is the only the layout algorithm and any code for converting text into words and rendering the final output requires additional development.

Word Cloud Generator, word words sprite placed layout algorithm area without step bounding retrieve overlap is available on GitHub under an open source license as d3-cloud. Jason Davies’ is a Wordle-inspired word cloud tool layout written in JavaScript and available on GitHub under an open source license as d3-cloud. It’s layout algorithm focuses on positioning words without overlap, allowing you to tweak parameters like scale and angle of inclination. Another perk is that you can export your word cloud in SVG.

word cloud / Paweł Borowski / Observable, The layout algorithm for positioning words without overlap is available on GitHub under an open source license as d3-cloud. Note that this is  Watch the wordcloud component in action on the demo page. How to use Install bower $ bower install angular-d3-word-cloud angular.js, d3.js, d3.layout.cloud.js would be install as dependencies auto. If it won't for some error, install it manually. $ bower install angular $ bower install d3 $ bower install d3-cloud npm $ npm install angular-d3

Comments
  • Agreed that there are difficulties. However, playing a bit with dimensions (layout and svg ones) and font family, it is possible to reach just occasional and relatively mild overlaps (but how acceptable those overlaps are can be a bit subjective). In any case, here is a plunk that I created to play with it. At the very least, I believe these dimensions improved on the exclusion of words...looks like most of them are there (although they would need to all be there).
  • Yeah, thank you. You changed the dimensions and the font as far as I see? It does work quite okay for the example. However, I really would like to solve the problem in general. I'm actually quite surprised that it happens as the whole point of the word cloud layout should be to avoid overlaps and I saw a lot of praise for it.
  • You're right. That's all I did. And agree with you, a general solution is what is needed. We might be missing something...I have not had time to delve on it too deeply. You could also write an email to Jason.
  • No, it just resized the distribution of the words on the screen and made the box even smaller causing more overlap
  • COMMON ISSUE: not anchoring the SVG text to the center, .attr("text-anchor", "middle")
  • problem stays in my case