Get Acquainted With WordCram

(2010-09-27: Updated for WordCram 0.2.)

WordCram is customizable, but you have to know how it works, what each piece does, to get what you’re after.

The whole idea of a word cloud is to draw a bunch of words according to their weight. With WordCram, you hand it the weighted words and your Processing sketch, and it’ll generate the word cloud image for you.

WordCram’s drawAll() method draws all the words at once. (This can take a while if you feed it a lot of words.) Or if the WordCram hasMore() words to draw, you can use drawNext() to draw them one-by-one. Try calling drawNext() once per frame, and you can watch WordCram position each word.

// Draw them all at once (might take a while):
wordcram.drawAll();

// Or, draw them individually:
if (wordcram.hasMore()) {
   wordcram.drawNext();
}

Weighting Words

Word clouds often illustrate word frequency in some piece of text: more frequent words are bigger, giving you a rough idea what the text is about. WordCram comes with a TextSplitter that counts up the words in any String or String array, which works well with Processing’s loadStrings(filename) method:

Word[] weightedWords = new TextSplitter().split(loadStrings("lotsOfText.txt"));

But WordCram can accept any array of Word objects, so you can make your own array with whatever values you like:

Word[] populationSizes = new Word[] {
    new Word("China", 1339360000),
    new Word("India", 1187340000),
    new Word("USA", 310192000),
    ...
};

Future plans include loading weighted Words from your delicious tags, a web page, a Twitter stream, and an RSS feed.

Getting the Look You Want

When creating a word cloud, it’d be nice if you could pick each word’s font and color, and say about where in the picture it should go, and what angle it should be at. WordCram lets you do that. You give it a WordColorer, and when WordCram is ready to draw “careening” (weight 0.4317), it’ll ask the WordColorer what color to draw it in. You can get WordColorers from the Colorers class:

WordCram wordcram = new WordCram(...
    // garish Christmas colors
    Colorers.pickFrom(color(255,0,0), color(0,255,0)),
    ...);

WordCram otherWordcram = new WordCram(...
    // three grays
    Colorers.pickFrom(color(50), color(125), color(200)),
    ...);

Besides the WordColorer, a WordCram needs a WordFonter, a WordPlacer, a WordAngler, and a WordSizer. Each one has a corresponding class with some pre-fabs, to get you started:

pre-fab class methods
Colorers pickFrom(), twoHuesRandomSats()
Fonters pickFrom(), alwaysUse()
Placers horizLine(), centerClump(), upperLeft()
Anglers pickFrom(), alwaysUse(), random(), horiz(), mostlyHoriz(), upAndDown(), hexes()
Sizers byWeight(), byRank()

Colorers and Fonters

As we’ve seen, WordColorers tell WordCram how to color each word. Colorers.pickFrom() can take any number of Processing colors, and will return one at random. Colorers.twoHuesRandomSats() picks two random hues, and randomly saturates one of them for each word. You have to pass it the Processing sketch, so it can use the sketch’s color() method: Colorers.twoHuesRandomSats(this).

WordFonters tell WordCram which PFont to use for each word. Fonters.pickFrom() words like Colorers’ version — it can take any number of PFonts. Fonters.alwaysUse() will always use the PFont you give it.

Placers

Placers are more complicated, but only a little bit. They give WordCram the x and y coordinates where each word should appear, as a PVector. (The word won’t appear exactly there, it’ll be nudged a bit until it doesn’t overlap with other words.) Placers.horizLine() tries to place words along the horizontal axis, Placers.centerClump() places them in more of a circle, and Placers.upperLeft() puts them all in the corner.

Placers are a weak spot for WordCram right now — I’m not entirely happy with most of them, and I expect the guts of WordCram that use Placers to change in the future. That said, the existing Placers, and how you use them, will probably stay the same. (Hopefully they’ll just work better.)

Anglers

Anglers tell WordCram what angle each word should be drawn at, specified in radians. Right now there are more pre-fab Anglers than anything else, but they’re all pretty simple.

pickFrom() and alwaysUse() work just like they do for Fonters. random() will return a random angle for each word. horiz() makes them all horizontal, but mostlyHoriz() draws a few going up and down, and upAndDown() draws them all up and down. hexes() puts them all on increments of 60°, so it looks something like a snowflake or a hex grid.

Sizers

Sizers tell WordCram what size to draw each word in. Their answer is passed to Processing’s textFont method, along with the PFont returned by the Fonter. The two built-in Sizers, byWeight and byRank, both take a minimum and maximum size. (A word’s weight is its frequency; when you sort words by their weight, a word’s rank is its order in the list.)

Eventually, WordCram will have a “smart sizer” that decides how to size words based on the size of your sketch, the number of words, and the distribution of their weights, but you’ll always be able to use a different one if you need to.

Rolling Your Own

There’s nothing special about those built-in components — if you don’t like any of them, you can roll your own. For instance, here’s a WordSizer that makes “careening” huge, and everything else tiny.

class CareeningBigWordSizer implements WordSizer {
   public int sizeFor(Word w, int wordRank, int wordCount) {
      if (w.word.equals("careening")) {
         return 300;
      } else {
         return 3;
      }
   }
}

(If that looks weird, don’t sweat it — you can always use the built-ins. But if you’re curious, and you really want to use WordCram to the fullest, reading about Java’s interfaces or the Strategy pattern should get you started.)

Each one is an interface with only one method:

interface its only method
WordColorer int colorFor(Word w)
WordFonter PFont fontFor(Word w)
WordPlacer PVector place(Word w, int wordIndex, int wordsCount, int wordImageWidth, int wordImageHeight, int fieldWidth, int fieldHeight)
WordAngler float angleFor(Word w)
WordSizer float sizeFor(Word w, int wordRank, int wordCount)

That’s It!

There’s not much more to WordCram. I might do a tutorial about WordCram’s innards (bounding box trees, collision detection, and nudging words), but you don’t need to know about all that unless you’re in the innards, or rolling your own WordPlacer, and that’s another tutorial.

If anything doesn’t make sense, let me know, and I’ll do my best to clear it up.

Advertisements
This entry was posted in tutorial. Bookmark the permalink.

24 Responses to Get Acquainted With WordCram

  1. Lee says:

    Hi,
    I am learning java and I want to create a word cloud at my website.
    Can you give me a very simple example to create them by using html and java.
    Thank you so much
    Lee

  2. Hi Lee,

    Sure – check out my BarCamp Boston 6 word cloud sketch, it’s a pretty simple example. An even simpler one is included in the examples (In Processing, under File > Examples > Contributed Libraries > WordCram > tutorial), called A_loadingWords.pde – or you can read the code in the on-line repo. Both of those make a word cloud from a URL.

  3. Tann says:

    Hi,

    I am trying to embed a wordcram PApplet into a JFrame. However, after it loads an weighted words array, it draws but then blinked and disappeared.

    JFrame frame = new JFrame ();
    PApplet applet = new MyWordCramApplet();
    frame.add (applet);
    applet.init();
    frame.show();
    ..

    Thanks.
    Tann

  4. That’s odd – does the same happen with a non-wordcram processing sketch? Does the processking sketch w/ wordcram in it run normally, outside of the JFrame?

  5. Tann says:

    I used to work with Wordookie and it was ok.

    Wordcram sketches run ok though.

  6. Tann, feel free to open a ticket at http://github.com/danbernier/WordCram, and attach all the relevant code. If you don’t have a github account, feel free to email me: wordcram (at) gmail.

  7. Tann says:

    it works great with PApplet.main here.

    static public void main(String args[]) {
    PApplet.main (new String[] { “–present”, “–bgcolor=#000000”, “–stop-color=#cccccc”, “MyWordCramWordCloud”});
    }

  8. Hmm, mine ran fine with this:

    static public void main(String args[]) {
        PApplet.main (new String[] { "--present", "--bgcolor=#000000", "--stop-color=#cccccc", "example.Main"});
    }
    

    Is your MyWordCramWordCloud class inside a package?

  9. Tann says:

    Hi Dan

    The problem is actually running the sketch inside my Swing application.

    I have a thread that compute, output data into a file and draw the word cloud.

    JPanel sketchPanel = app.mainframe.getWordCloudPanel();
    PApplet papplet = new MyWordCramCloud(dataFile, wordcram.Placers.wave(), 1024, 800);
    sketchPanel.add(papplet);
    papplet.init();

    //If I don’t do the following code, the cloud will blink and nothing is displayed.
    //However, if I insert the code, the word cloud gets displayed BUT it freeze my application for as long the wordcram needs to draw the cloud.
    while (!papplet.finished)
    try {Thread.sleep(5);} catch (Exception e) {}

    app.mainframe.repaint();

    Any idea to overcome this? Thanks.
    Tann

  10. Hi Tann,

    It’s really hard to say what’s going on here, without knowing what MyWordCramCloud looks like, or what dataFile is.

    I’d say look carefully at your Swing code, and try to understand what’s going on there: you’ve already got WordCram running successfully, and the Swing is the main thing that’s changing, so that’s most suspicious.

  11. Ashish says:

    What is licence information for this software .. we are planning to use this in one of project

  12. Sofie says:

    Is it possible to use the wordcloud with the html5 canvas?

  13. Nope – right now, WordCram relies pretty heavily on traditional Processing, and doesn’t work with Processing.js or other javascript/html technologies. I’d love to someday port it to javascript, though…

  14. Ash says:

    HI, Is it possible to print out the word, the rank of the word and the frequency in the console? For example: Kari, 1, 1400

  15. Lance says:

    Hi,
    wordcram is not drawing all my words and would output – “coulndn’t find a spot” or “shape was too small” when clearly there was a lot more space since I increased size of the window.

    Is there any way to forcefully show all the words? or somehow get it to fill some of the white spaces that can be seen.

    Either that or i will have to use Paint to add them into the image manually 😦

    Really amazing program btw 😀

    Cheers,

    Lance

  16. Yeah, that should be no problem – just iterate through wordcram.getWords(), and print them out. Here’s a very rough sketch:

    Word[] words = wordcram.getWords();
    for (int i = 0; i < words.length; i++) {
    Word word = words[i];
    println(word.word + ", " + i + ", " + word.weight);
    }

  17. If you have a github account, report it as an issue, with a sample sketch that causes the problem.

    If you don’t, you can just comment here w/ the sketch.

  18. Keesjan says:

    Hi, Iam interested to in a port to html 5. Any plans?

  19. Still no firm plans. Jason Davies has a very nice word cloud javascript library, though, which I’d probably base the WordCram port on: http://www.jasondavies.com/wordcloud/

  20. andrei1up says:

    Hello,

    I do not have any knowledge in java or any programing code, except for some very basic knowledge in C++, but I would like to make a word cloud and then convert it into a tiff, jpg,png,bmp format that I could set as my website’s background. Is that do-able and if so I would be very grateful if you would take the time to explain how.

    Thank you henceforth.

    Best Regards,

    Andrei

  21. Sure, that’s exactly what WordCram does. Take a look at the tutorials it comes with, and you should be all set.

  22. Mike says:

    Hello!

    I’m looking to pass command line arguments to wordcram so that I can automatically generate png word cloud specifying the file to read from and output to using program arguments. I’ve been trying to do this in eclipse, but args in the IDE examples that you have don’t seem to contain any of the arguments I pass in run configurations in eclipse. Do you know if it is possible to pass args through eclipse?

    Also, thanks a lot for this great application.

    Regards,

    Mike

  23. You can’t pass command-line args directly to WordCram, because it has no executable.

    But you can make an executable wrapper (base it on the IDE examples that come with WordCram), and it can read command-line args & pass them to WordCram as needed.

    FYI, it’ll still pop up an Applet somewhere – AFAIK, you can’t really run Processing “headless.” But that’s usually only a concern if you’re trying to run on a server.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s