Standing Out From the Cloud: How to Shape and Format a Word Cloud | by Andrew Jamieson | Towards Data Science

This blog will cover Word Clouds, their limitations, followed by some formatting examples.
Word Clouds are a straightforward way to summarize text and make the most popular words jump to your attention. They are eye-catching and easy to understand without the need for any additional explanation.
However, Word Clouds do have limitations. They are not helpful for an in-depth analysis. They may be more attractive to look at than a simple bar chart — but they provide far less information. Here are some of the problems with Word Clouds.
Font size is not an effective way to show differences. We can distinguish between large, medium, and small fonts; beyond that, it gets tricky.
We don’t know how the words are weighted — what does a large font actually mean? Does the word with the large font occur 10 times or 1000 times?
Positioning in visualization is usually very important. However, in Word Clouds, the word order is at random.
Longer words receive greater emphasis than shorter words because their length takes up more space.
We don’t learn anything about the context of the words. In some cases, the opposite meaning is highlighted — for example, the phrase “not good” would be represented on a Word Cloud as “good” after the stopword of “not” is removed.
Despite these limitations, Word Clouds have become incredibly popular, primarily because they are easy to create. The popularity and drawbacks of Word Clouds mean that they have many detractors — my favorite Word Cloud (or “Tag Cloud”) insult is that they are “the new mullets”... ouch.
You didn’t read this blog to learn about how terrible Word Clouds are. There are plenty of other blogs for that. Words Clouds are an excellent tool for drawing attention. They are handy as an introduction and to break up heavy text passages. So, how do you make your Word Cloud jump out from the cloud?
For these examples, I will use an Emoji from OpenMoji and text about emojis from Wikipedia to form the cloud.
“A yellow face with simple, open eyes and a thin, closed smile. Conveys a wide range of positive, happy, and friendly sentiments. Its tone can also be patronizing, passive-aggressive, or ironic, as if saying This is fine when it’s really not.”
https://emojipedia.org/slightly-smiling-face/
Here are the libraries to use
from PIL import Imagefrom wordcloud import WordCloud, STOPWORDS, ImageColorGeneratorimport matplotlib.pyplot as plt%matplotlib inlineimport numpy as np
# Default WordCloudwordcloud = WordCloud().generate(emoji_text)  plt.figure(figsize=(10,6))plt.imshow(wordcloud)plt.axis(“off”)plt.show()
wordcloud = WordCloud(max_font_size=80, max_words=1000, background_color=”black”, colormap=’Paired’).generate(emoji_text)# Use the lasst four lines from above (plt) to plot the Word Cloudplt...
Here we have changed some of the default parameters — using background_color, max_font_size, and colormap — any Matplotlib palette will work and setting the font.
In this example, I’m also using font_path to choose a custom font. You set this to the file location of your chosen font. For example:
font_path = “/Users/You/Fonts/Comfortaa-Bold.ttf”
WordCloud also has a built-in list of stopwords that you can ignore, adjust, or use like this:
stopwords = set(STOPWORDS)
You can create a shape for your word cloud by using a mask. First, upload a png image and convert it to an array. Wordcloud will draw words in positions where the image is not white. In the array, 255 is white, and 1 is black.
mask2 = np.array(Image.open("paint1a.png"))emo2 = WordCloud(font_path = font_path, background_color="white", max_words=100, mask=mask2, stopwords=stopwords,               min_font_size=10, colormap='Dark2')# Generate a wordcloudemo2.generate(emoji_text)# plt ...
If your image has a transparent background, it will throw an error.
ValueError: bad transparency mask
The mask needs the white value to be 255 and not 0. You can inspect your image by looking at the array.
emoji_mask = np.array(Image.open(“1F642_color.png”))emoji_maskarray([[0, 0, 0, ..., 0, 0, 0],...,[0, 0, 0, ..., 0, 0, 0]], dtype=uint8)# replace 0 with 255emoji_mask[emoji_mask == 0] = 255emoji_maskarray([[255, 255, 255, ..., 255, 255, 255],...,[255, 255, 255, ..., 255, 255, 255]], dtype=uint8)
You can also use the ImageColorGenerator function to set the colormap to match the image. (The dark patches are the eyes and mouth of our emoji. You may need to reduce max_font_size to improve the look of image details )
# note — need to set max font size, or font extends over the colorsmask = np.array(Image.open(“paint1.png”))emo_clr = WordCloud(background_color=”white”, mode=”RGBA”, max_words=3000, max_font_size=18, mask=mask).generate(emoji_text)# create coloring from imageimage_colors = ImageColorGenerator(mask)plt.figure(figsize=[7,7])plt.imshow(emo_clr.recolor(color_func=image_colors), interpolation=”bilinear”)plt.axis(“off”)plt.show()
The emoji does show how the color effect works, but it isn’t a great example. The yellow color barely shows up on the white background, and it is impossible to read the words. In order to show the definition of the eyes and mouth, this Word Cloud uses a massive max word count and a small maximum font. I recommend that you experiment with color and make the fonts as large as possible while maintaining the borders of each color. Some images work better than others — colors in straight lines work better than colors with curves.
Some images will generate an error when you use color.
NotImplementedError: Gray-scale images TODO
The color function looks for a three-channel array, representing values for red, green, and blue (RGB). Some images only have one channel. You can solve this by adding two extra channels to the array — see Matthew Arthur’s blog post for a great example of how to do this.
Alternatively, I found that by opening the image in Paint or Paintbrush and resaving the image, it transforms into the expected format.
Check your image by inspecting the shape like this:
test = np.array(Image.open(“1F642_color.png”))test.shape(618, 618) # -> error example(618, 618, 3) # -> RGB example
Here’s a similar example, where I adjusted the NumPy array so that the emoji's eyes and mouth are left blank.
mask2 = np.array(Image.open(“paint1.png”))mask3 = np.where(mask2==0, 255, mask2)emo = WordCloud(background_color=”white”, max_words=500, mask=mask3, stopwords=stopwords, colormap=’Dark2')emo.generate(emoji_text)
Finally, you can also experiment with a reverse image. Here we plot the word cloud around a shadow rather than inside a shape. I tweaked this image in MS Paint, reversing the colors, so I had a black outline around a white circle. Finally, I opened it in Python and loaded it as a Word Cloud — the code is the same.
Once you have Word Cloud outline, you can drop the original image on top, like this.
Word Clouds are an excellent way to draw attention to your work. They can be a good lead-in to more in-depth analysis. There are many different ways that you can adjust your Word Cloud and make it unique to your project, rather than restricting yourself to the defaults. I hope that this blog's examples will give you a starting point to create your own Word Clouds.