Building a word cloud from text
A word cloud is three ordinary steps: tokenise, count, and map counts to type size.
Tokenising and counting
Splitting on non-letter characters and lowercasing produces the token list. Counting is a single pass into a map. The result is a frequency table, and everything visual afterwards is a rendering of that table.
Stop words dominate any raw count, so a stop list is not optional. Beyond that, collapsing plural and inflected forms to a common root prevents the same idea appearing three times at three sizes.
Mapping counts to size
Type size should come from a scale whose domain is the observed count range. A linear mapping is honest but, because word frequencies are heavily skewed, it usually renders one enormous word and a field of unreadable ones. A square-root or logarithmic mapping compresses the top end and keeps the tail legible.
Area, not height, is what the eye compares, which is another reason the square root behaves better than the raw count.
Placement
The layout places the largest word first and works down, testing candidate positions along a spiral and keeping the first that collides with nothing already placed. Placement is therefore a search, and it can fail: if the canvas is too small some words are simply dropped.
Because the search runs asynchronously, the drawing code has to wait for the layout's completion event rather than drawing immediately after starting it.
From raw text to a drawn cloud
- Lowercase the text and split it on non-letter characters.
- Drop stop words and anything shorter than three characters.
- Count the remaining tokens into a frequency map and keep the top entries.
- Build a square-root scale from the count range to the type size range.
- Run the layout with those sized words and wait for its completion event.
- Draw the placed words, rotating each by whatever angle the layout assigned.
var size = d3.scaleSqrt()
.domain([minimumCount, maximumCount])
.range([12, 72]); // pixels of type sizeCompressing a skewed count range