Monogram mark of Manish Shivanandhan
Manish Shivanandhan
Full Stack Web, Deep Learning & D3 Visualizations Engineer

Building a word cloud from text

D3 and data visualisation · applies to: Text processing, D3 layouts · last updated 2016-05-23

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

  1. Lowercase the text and split it on non-letter characters.
  2. Drop stop words and anything shorter than three characters.
  3. Count the remaining tokens into a frequency map and keep the top entries.
  4. Build a square-root scale from the count range to the type size range.
  5. Run the layout with those sized words and wait for its completion event.
  6. 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 size

Compressing a skewed count range

Worth knowingWords missing from the finished picture were not filtered out; the placement search ran out of room for them, so widen the canvas before changing the filter.

Return to D3 and data visualisation