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 numpy

The 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 processing

Pass scale=2 to the constructor for a high-resolution PNG without changing the layout.

Common problems

SymptomFix
Whole canvas filled despite a maskBackground isn't pure white (255). Flatten transparency and threshold as above.
Non-Latin text shows as boxesPass 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 wordsSegment first (e.g. with jieba for Chinese) and join tokens with spaces.
Layout changes every runSet 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.