Open john-guerra opened 10 years ago
We are running into this problem too. I think either solution suggested above would work. Has anyone implemented one of them? Although these words are often the highest ranking ones, they could occur anywhere in the list.
I implemented an overflow option here https://github.com/john-guerra/d3-cloud
@john-guerra I tried to replace my version of the layout with your version, and while it does work the scaling and arrangement seem a bit off.
It does not seem to take all available width into account.
See pictures below to see what I mean.
@tribe84 your solution looks cool, have you posted your code somewhere?
@john-guerra nice job on the overflow code.
Thanks a lot!
On Mon Jan 26 2015 at 12:54:19 PM Sanders DeNardi notifications@github.com wrote:
@john-guerra https://github.com/john-guerra nice job on the overflow code.
— Reply to this email directly or view it on GitHub https://github.com/jasondavies/d3-cloud/issues/36#issuecomment-71536165.
Hi, i've runned into this problem at first, too. But i noticed when you set a domain, the words won't get drawn bigger than your range value:
var fontScale = d3.scale.linear() .domain([words min size, words max size]) .range([min font size, max font size]);
See this fiddle for an example: http://jsfiddle.net/ndenmhhw/3/
While this doesn't change the Issue, that the words won't get drawn when they are bigger than the height/width, it let's you controll it through the size parameters.
hope this helps someone
I ran into the same problem as @tribe84. That forced me to rethink my approach to this issue. I ended up increasing the layout space in the place function, such that it is no longer checks sizing bounds but enlarging sizing bounds. Of course I scale my entire SVG on the subsequent draw method. I understand that this solution is not ideal but it seemed to work for me.
+1 this feature is super needed
My fix was to create a maximum font size based on the largest size and scale all other words point size. I found that the words are always visible. If you want a larger size simply adjust the maxFontSize variable...
Example:
//add a variable or dynamically control this value from an input box var maxFontSize = 36;
d3.layout.cloud().size([width, height]) .words(tags.map(function (d) { return { text: d.text, size: d.size }; })) .padding(1) //.rotate(function () { return ~~(Math.random() * 2) * 60; }) .rotate(function (d) { return 0; }) .text(function (d) { return d.text; }) // THE SOLUTION .font("Impact") .fontSize(function (d) { //THE SOLUTION PART II //restrict font size to max of 36 //largest size / word current size * maxFontSize //Example: 1st word is Canada and size is 444. Calculation is 444/444 = 1 * 36 sets largest word to 36 (points) //Example: 2nd word is item and size is 327. Calculation is 327/444 = 0.734 * 36 = 26.5 (points) return eval(d.size / largest_size * maxFontSize); }) .on("end", draw) .start();
Having the same issue. If I have long words they are just left out depending on the position of the other words. Specifying a max font size is not really helping because short words are then very small even they could be a lot bigger...
+1
+1 @supaMUC
@eformx I don't see how Canada
would get a size of 444 in your example. If you set the largest font size to 36, how does your solution prevent that a really long word like blablablablablablabla
would fall off?
You need one more calculation in there.
Max size of div / # characters = max pixels per character then you would need to figure out the size/character for the font you are using at each font size.
This might help. http://websemantics.co.uk/resources/font_size_conversion_chart/
So, the above calculation will actually give you the max font sized based on the longest word with the highest value.
I found a way of fixing this issue.
I confirm that all words are rendered by the recursive strategy.
edited http://jsfiddle.net/ndenmhhw/3/
var words = [
"Hello", "world", "normally", "you", "want", "more", "words",
"than", "this"].map(function(d) {
return {text: d, size: 10 + ~~(Math.random() * 90)};
}).concat([{text:"OneBigWord", size: 150}]);
maxSize = d3.max(words, function(d) { return d.size; });
minSize = d3.min(words, function(d) { return d.size; });
function drawcloud (range_max) { // declare the function
var fontScale = d3.scale.linear()
.domain([minSize, maxSize])
.range([5, range_max]); // the argument here
var fill = d3.scale.category20();
d3.layout.cloud().size([300, 300])
.words(words)
.padding(5)
.rotate(function() { return ~~(Math.random() * 2) * 90; })
.font("Impact")
.fontSize(function(d) { return fontScale(d.size) })
.on("end", function(output) {
if (word.length !== output.length) { // compare between input ant output
drawcloud ( range_max - 5 ); // call the function recursively
return undefined;
}
else { draw(output); } // when all words are included, start rendering
})
.start();
function draw(words) {
d3.select("body").append("svg")
////
//// please refer http://jsfiddle.net/ndenmhhw/3/
////
}
Although it does not always fit your situations, it might help some people annoyed with this issue And I hope that this issue is solved in the d3-cloud.
@satotake that looks like a decent idea for a solution. Although the jsfiddle you link is currently broken and doesn't render anything. Probably best to load d3-cloud from github rather than jasondavies.com.
Building on examples above, I've successfully implemented sorting and sizing of the words by frequency of appearance with duplicate removal: http://codepen.io/znak/details/rOgXoV/
As for the max font size for the biggest word, it could be done with measureText()
method.
hi @john-guerra i used your algorithm but its performance is not good. Kindly help me in that.
@BhumikaSarswat I'm sorry but your request is too vague
Any update on this?
@satotake @axelson I fix satotake's broken jsfiddle http://jsfiddle.net/rnz0khfx/
@jasondavies I try to make that word size is bigger proportionately word frequency like cool, nice and fabulous jasondavies's (https://www.jasondavies.com/wordcloud/)
I really wonder how do I make it? Is it possible with this d3-cloud api?
Here is my best to make now below based on satotake's
function wordFrequency(words){
var newArray = [];
var wordObj;
words.forEach(function(word) {
wordObj = newArray.filter(function (w){
return w.text == word;
});
if (wordObj.length) { wordObj[0].size += 1; }
else { newArray.push({text: word, size: 1}); }
});
return newArray;
};
var words = $("#data").data("words");
var regExp = /[\{\}\[\]\/?.,;:|\)*~`!^\-_+<>@\#$%&\\\=\(\'\"]/gi;
words = words.replace(regExp, '').split(' ');
words = wordFrequency(words).map(function(d) {
return {text: d.text, size:50 * ( 1+Math.sqrt(d.size) )};
})
Satotakes and samkugij jsfiddle did not include his proposed workaround using recursive calls. Here is a enhanced jsfiddle http://jsfiddle.net/ymmh9dLq/
Wow, I just stumbled on the same issue in 2018. Thanks for your posts... :-)
I implemented an overflow option here https://github.com/john-guerra/d3-cloud
hello @john-guerra can you provide this expmple in d3 v5? if I am try to run this exaplme in d3 v5 its noy working
Sorry I don't have the cycles right now
John. From my phone, brevity and all http://johnguerra.co
On Tue, Oct 8, 2019, 9:24 AM khushbu notifications@github.com wrote:
I implemented an overflow option here https://github.com/john-guerra/d3-cloud
hello @john-guerra https://github.com/john-guerra can you provide this expmple in d3 v5? if I am try to run this exaplme in d3 v5 its noy working
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jasondavies/d3-cloud/issues/36?email_source=notifications&email_token=AAJJCS5O4IC7QWSHBPUFBDTQNSJZZA5CNFSM4AOSCJC2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEAULIPQ#issuecomment-539538494, or mute the thread https://github.com/notifications/unsubscribe-auth/AAJJCS5WBUMTPILEFE6IZNLQNSJZZANCNFSM4AOSCJCQ .
Right now the algorithm leaves out words that are too big to fit on the available width/height. This is OK for smaller words that aren't that important, but it also leaves out the most important words on a cloud without any warning.
http://jsfiddle.net/duto_guerra/VNurQ/
I can think of two solutions:
I was planning on trying to do this myself and send you a pull request, but I would like to hear your preferences and opinion
John