Word cloud in Python
A practical guide to the wordcloud library: from a five-line example to shaped, recoloured clouds built from a pandas DataFrame.
Install
pip install wordcloud matplotlib pillow numpyThe wordcloud package, created by Andreas Mueller, ships prebuilt wheels for current Python versions on Windows, macOS and Linux.
The basic word cloud
from wordcloud import WordCloud
import matplotlib.pyplot as plt
text = open("speech.txt", encoding="utf-8").read()
wc = WordCloud(width=1600, height=900, background_color="white").generate(text)
plt.figure(figsize=(12, 7))
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.show()
wc.to_file("wordcloud.png")generate() tokenises the text, drops the built-in English stopwords, counts words (and common two-word phrases, via collocations=True) and lays them out. interpolation="bilinear" smooths the image in matplotlib.
Stopwords and word limits
from wordcloud import WordCloud, STOPWORDS
stop = STOPWORDS | {"said", "will", "also", "one"}
wc = WordCloud(
stopwords=stop,
max_words=100, # keep the top 100
min_word_length=3, # skip very short tokens
collocations=False, # single words only, no "New York" pairs
relative_scaling=0.5, # 0 = rank only, 1 = strictly proportional to count
).generate(text)relative_scaling controls how strongly size follows frequency — the same trade-off shown in the interactive size demo. The default of 0.5 mixes rank and frequency.
Custom shapes with a mask
import numpy as np
from PIL import Image
img = Image.open("heart.png").convert("RGBA")
bg = Image.new("RGBA", img.size, "WHITE")
mask = np.array(Image.alpha_composite(bg, img).convert("L"))
mask = np.where(mask > 200, 255, 0).astype(np.uint8) # pure white = outside
wc = WordCloud(mask=mask, background_color="white",
contour_width=3, contour_color="#e8317a").generate(text)
wc.to_file("heart-cloud.png")The rule to remember: pixels with value 255 are outside the shape. Transparent PNGs load as black, which fills the whole canvas — that's why the code flattens the image onto white first. When a mask is set, width and height are ignored and the mask's size is used.
Colours
# any matplotlib colormap
wc = WordCloud(colormap="viridis").generate(text)
# colours sampled from a picture
from wordcloud import ImageColorGenerator
photo = np.array(Image.open("sunset.jpg"))
wc = WordCloud(mask=mask).generate(text)
wc.recolor(color_func=ImageColorGenerator(photo))
# one fixed colour
wc.recolor(color_func=lambda *args, **kwargs: "#1f7f9c")For ImageColorGenerator, the colour image must be at least as large as the cloud canvas.
From a pandas DataFrame
import pandas as pd
df = pd.read_csv("survey.csv")
# raw answers in one column
wc = WordCloud().generate(" ".join(df["answer"].dropna().astype(str)))
# already counted: columns "word" and "count"
freqs = df.set_index("word")["count"].to_dict()
wc = WordCloud().generate_from_frequencies(freqs)Saving
wc.to_file("cloud.png") # PNG at width×height (times scale)
svg = wc.to_svg(embed_font=True) # vector output
open("cloud.svg", "w", encoding="utf-8").write(svg)
arr = wc.to_array() # numpy array for further processingPass scale=2 to the constructor for a high-resolution PNG without changing the layout.
Common problems
| Symptom | Fix |
|---|---|
| Whole canvas filled despite a mask | Background isn't pure white (255). Flatten transparency and threshold as above. |
| Non-Latin text shows as boxes | Pass font_path to a font that covers the script, e.g. a Noto font. |
| Same word appears twice (“data” and “data science”) | Set collocations=False. |
| Chinese or Japanese text isn't split into words | Segment first (e.g. with jieba for Chinese) and join tokens with spaces. |
| Layout changes every run | Set random_state=42. |
Skip the code
Need one image, not a pipeline? The CloudShaper generator does the same steps in the browser — stopwords, masks from your own image (word art generator), weighted lists and SVG export — and the frequency counter gives you a CSV of counts to feed into generate_from_frequencies.
Questions people ask
What is the best Python library for word clouds?
The “wordcloud” package by Andreas Mueller (pip install wordcloud). It handles counting, stopwords, masks, colours and export, and works with matplotlib and Pillow. It is the de facto standard.
Why is my mask not working in wordcloud?
In the wordcloud library, pure white pixels (255) are treated as “outside” and everything else as “inside”. A mask with a transparent background loads as black, so the whole canvas is filled. Flatten the image onto white first, or convert it so the background is exactly 255.
How do I remove stopwords in a Python word cloud?
Pass stopwords=STOPWORDS (the built-in English set) or your own set, e.g. stopwords=STOPWORDS | {"said", "will"}. For other languages, use NLTK’s stopword lists.
How do I make a word cloud from a pandas column?
Join the column into one string — " ".join(df["answers"].dropna()) — and call generate(). If you already have counts, build a dict with df.set_index("word")["count"].to_dict() and call generate_from_frequencies().
Is there a way to do this without code?
Yes — CloudShaper does the same steps in your browser: paste text, pick a shape (or upload a mask image), and download PNG or SVG.