# Wordle-like word clouds

Wordle creates word clouds based on the frequency on words in a text, similar to tag clouds. What makes it unique is that it can lay out words in arbitrary directions without too much white space. See the gallery for many examples.

Given a list of words together with their frequency, is there some package that provides at least some of the functionality in (La)TeX? If not, is there some way to abuse the TeX layout engine to produce word clouds?

(This is not meant as advertisment for wordle, I just do not know of anything that is similar.)

-
I feel a TikZ-related reply coming on ... –  Loop Space Aug 3 '10 at 18:28
No problem, I like TikZ :) –  Caramdir Aug 3 '10 at 18:36
A nice example, although with some missing code: tex.stackexchange.com/a/146178/1952 –  Ignasi Aug 1 '14 at 8:19

Most word cloud generator simply generate a scaled word according to its relative frequency in the text, and then pack everything together in a nice way. Wordle really shines in using the shape of each letter rather than the bounding box. That is the reason that the resultant word clouds have very little white space.

AFAIU, TeX only knows the bounding box of a word. So, even if the wordle algorithm were known (is it?), we need more hooks to implement it in TeX. Perhaps luatex+mplib can be used to access the shape of the glyph, but I do not know the details.

The easier option is to use worldle to generate a png and simply include the png in your tex file. The java file for the engine that powers wordle is available from http://www.alphaworks.ibm.com/tech/wordcloud (you need to register first). Then, it is a simple matter of providing some plumbing so that

\begin{wordle}
lots of text
\end{wordle}


stores the text in an external file, runs it through wordle, and includes the resultant png. For example, if you want to do this in ConTeXt

1. Download the IBM Word Cloud engine. After unzipping the files, I removed spaces from the folder names and renamed it to "IBM-Word-Cloud".

3. Then you can create word clouds as follows

    \usemodule[filter]

\defineexternalfilter
[wordcloud]
[filtercommand=/opt/java/jre/bin/java -jar $HOME/IBM-Word-Cloud/ibm-word-cloud.jar -c$HOME/IBM-Word-Cloud/examples/configuration.txt
-w 800 -h 600
-o \externalfilteroutputfile\space
-i \externalfilterinputfile,
output=\externalfilterbasefile.png,
continue=yes,
]

\def\ExternalFigure#1{\externalfigure[#1]}


and then use

 \startwordcloud
lots of words
\stopwordcloud


See this blog post for more details.

-
I didn't know that the wordle engine was available for download. Thanks for the link! –  Caramdir Aug 3 '10 at 21:39
A proof of concept: randomdeterminism.wordpress.com/2010/08/03/… and a working example (with ibm-word-cloud.jar moved to $HOME/bin and configuration.txt moved to$HOME/.config/IBM-Word-Cloud) github.com/adityam/filter/blob/master/tests/wordcloud.tex –  Aditya Aug 3 '10 at 23:04
Thank you again. Could you please add the link directly to the answer (so that it is more obvious for other people coming here, e.g. via google). –  Caramdir Aug 4 '10 at 10:49
I added actual code in the answer with a link to the blog post. –  Aditya Aug 4 '10 at 14:18
Is there a way of generating a wordle image that isn't a bitmap? –  András Salamon Aug 4 '10 at 19:23

This is my first post. Yesterday I saw this question and I made some PERL code. I know is not exactly the same than you want, and I know it would be better to do it in TeX, but maybe this is useful for some people. It has two options:

• Make wordcloud of index entries:

./latextotagcloud.pl index file.tex > file.html

• Make wordcloud of cite authors:

./latextotagcloud.pl citea file.tex > file.html

• Make wordcloud of cite documents:

./latextotagcloud.pl cited file.tex > file.html

NEW CODE (v 2.0) UPDATED OCTOBER 18, 2011 This new code allows color images I like them because a small word can be highlighted by it's color. I saw in monocolor clouds that long words catch eye because of it's width.

#!/usr/bin/perl -w
#v. 2.0
#(c) Xavier de Blas, 2011. This code is GPL 2.0.
use HTML::TagCloud_colors;

#recommended:
$background = "#ffffff";$color_small ="#333333"; $color_big ="#ff0000"; #alternatives #$background = "#000066"; $color_small ="white";$color_big ="red";
#$background = "#ffffff";$color_small ="#333333"; $color_big ="blue"; if( @ARGV != 2 or ($ARGV[0] ne "index" and $ARGV[0] ne "citea" and$ARGV[0] ne "cited") ) {
print STDERR "Usage:\n ./latextotagcloud.pl option file.tex > file.html     \n(option: index or citea or cited)\n";
exit(0);
}
$option = shift(@ARGV); open(IN,shift(@ARGV)); undef$/;
while(<IN>) {
if($option eq "index") { while($_ =~ /\\index{([^@!}\|]*)([^}]*)}/g) {
#   while($_ =~ /\\index{([^!}\|]*)([^}]*)}/g) {$matched = $1; unless ($2 =~ m/^\|see/) { #don't use the "see other concept" entries
$matched =~ s/ /-/g; #Converts: Index A B -> Index-A-B # if($matched =~ m/@/) { ($matchedSorting,$matched)=split(/@    /,$matched); }$seen{$matched}++; } } } elsif($option eq "citea") {
#next line gets "Bosco" in "Bosco1993", but "W3Schools" is written to match "W3Schools2001"
while($_ =~ /\\cite[^{]*{(W3Schools|[A-Za-z'\-]+)[^}]*}/g) {$seen{$1}++; } } elsif($option eq "cited") {
while($_ =~ /\\cite[^{]*{([A-Za-z0-9'\-]+)[^}]*}/g) {$seen{$1}++; } } } print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; print "<style type=\"text/css\">\n \@import url(latextotagcloud.css);\n</style>";$maxLevels = 1;
foreach(keys %seen) {
if($seen{$_} > $maxLevels) {$maxLevels = $seen{$_}; }
}
my $cloud = HTML::TagCloud->new(levels=>$maxLevels);
foreach(sort keys %seen) {
$latinized =$_;
$latinized =~ s/'a/á/g;$latinized =~ s/'e/é/g;
$latinized =~ s/'i/í/g;$latinized =~ s/'o/ó/g;
$latinized =~ s/'u/ú/g;$cloud->add("$latinized", "",$seen{$_}); } print$cloud->html_and_css();#if put a value, limit to that number of tags

open RFILE,">colors.R";
print RFILE "as.data.frame(colorRampPalette(c('$color_small', '$color_big'))($maxLevels+1))"; #ELMILLOR close RFILE; system("R CMD BATCH --slave --no-timing colors.R latextotagcloud_pre.css"); open CSSFILE1,"latextotagcloud_pre.css"; open CSSFILE2,">latextotagcloud.css";$/="\n";
line = 0; print CSSFILE2 "<style type=\"text/css\">\n #htmltagcloud { text-align: center; line-height: 1; } body { background:background; }
";

while(<CSSFILE1>){
unless($line == 0) {$_ =~ /#(......)/;
print CSSFILE2 "span.tagcloud" . ($line-1) ." a {text-decoration: none; color: #$1;}\n";
}
$line ++; } print CSSFILE2 "</style>"; close CSSFILE1; close CSSFILE2;  THIS IS THE OLD CODE (v 1.0) DO NOT USE! #!/usr/bin/perl -w #(c) Xavier de Blas, 2011. This code is GPL 2.0. use HTML::TagCloud; if( @ARGV != 2 or ($ARGV[0] ne "index" and $ARGV[0] ne "citea" and$ARGV[0] ne "cited") ) {
print STDERR "Usage:\n ./latextotagcloud.pl option file.tex > file.html \n(option: index or citea or cited)\n";
exit(0);
}
$option = shift(@ARGV); open(IN,shift(@ARGV)); undef$/;
while(<IN>) {
if($option eq "index") { while($_ =~ /\\index{([^@!}\|]*)[^}]*}/g) {
($underscored =$1) =~ s/ /_/g;   #Converts: Index A B -> Index_A_B
$seen{$underscored}++;
}
} elsif($option eq "citea") { #next line gets "Bosco" in "Bosco1993", but "W3Schools" is written to match "W3Schools2001" while($_ =~ /\\cite[^{]*{(W3Schools|[A-Za-z\-]+)[^}]*}/g) {
$seen{$1}++;
}
} elsif($option eq "cited") { while($_ =~ /\\cite[^{]*{([A-Za-z0-9\-]+)[^}]*}/g) {
$seen{$1}++;
}
}
}
my $cloud = HTML::TagCloud->new(); foreach(sort keys %seen) {$cloud->add("$_", "",$seen{$_}); } print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; print$cloud->html_and_css();


save in in a file named:

latextotagcloud.pl

and do:

chmod +x latextotagcloud.pl

you need to have libhtml-tagcloud-perl (and obviously perl) installed.

With new 2.0 code you will need R installed (eg. instal r-base on debian/ubuntu systems) With new 2.0 code you also need to modify libtagcloud. Instructions for Debian/Ubuntu:

1. dpkg -L libhtml-tagcloud-perl
2. Find: TagCloud.pm
3. In Linux Mint (Debian/Ubuntu) is here: /usr/share/perl5/HTML/TagCloud.pm
4. Go to /usr/share/perl5/HTML and copy the file:
5. sudo cp TagCloud.pm TagCloud_colors.pm
6. Change this in TagCloud_colors:
foreach my $level (0 ..$self->{levels}) {
my $font = 12 +$level;


To this:

my $fontMin = 12; my$fontMax = 36;
my $fontRang =$fontMax - $fontMin; foreach my$level (0 .. $self->{levels}) { #my$font = 12 + $level; my$font = $fontMin + ($fontRang * $level /$self->{levels} );


With this you will have an html cloud, to have it nicer in your document, you can:

1. Open in browser, print as PDF.
2. Open PDF in Inkscape, select all words (cutoff blank paper), properties (adjust to selection), print as PDF.
3. Include PDF in your LaTeX or LyX document.

Here is the result on the authors cited on my PhD document today (v1.0):

Result of (v2.0):

Maybe you can use the same and the connect to Wordle, I haven't done this because Worlde is not free software.

Hope it helps

-
(+1) Nice example. –  chl Jun 27 '11 at 15:03
The previous requires installing the following package: libhtml-tagcloud-perl –  user8632 Oct 16 '11 at 16:14
Can't exec "R": No such file or directory at ./latextotagcloud.pl line 67, <IN> chunk 1., is it looking for the statistics programme "R"? –  EricR Feb 13 '12 at 17:33
Nice. I know the lack of vertical words isn't as trendy, but it sure is a lot more readable. Good point about wordle not being free, too. –  naught101 Aug 2 '12 at 1:50