Introduction
A word cloud is the fastest way to answer “what is this text actually about?” — frequencies become font sizes and the dominant topics jump out instantly. This app takes pasted text or an uploaded file and renders a customizable word cloud: your colors, your stopwords, your shape. It is also a sneaky-good text-analysis primer, sitting between the raw reading of the sentiment analyzer and the charting of the Pandas dashboard.
The wordcloud library handles layout (fitting words without overlap) in C-speed; your job is feeding it clean text and good parameters.
Features
- Two inputs — paste text or upload a
.txt/.mdfile. - Stopword control — remove filler words, optionally add your own.
- Custom look — background color, colormap, and max words.
- Frequency table — top 15 words with counts beside the cloud.
- PNG download — export at full resolution.
Prerequisites
- Python 3.8+ — from python.org.
- Dependencies — install with pip:
pip install streamlit wordcloud matplotlib
Step 1: Create the Script
Save as wordcloud_app.py:
import streamlit as st
from wordcloud import WordCloud, STOPWORDS
import matplotlib.pyplot as plt
from collections import Counter
import re
st.set_page_config(page_title="Word Cloud Generator", page_icon="☁️")
st.title("☁️ Word Cloud Generator")
tab_text, tab_file = st.tabs(["Paste text", "Upload file"])
text = ""
with tab_text:
text = st.text_area("Your text", height=200, placeholder="Paste an article, essay, or transcript...")
with tab_file:
f = st.file_uploader("Upload .txt or .md", type=["txt", "md"])
if f:
text = f.getvalue().decode("utf-8", errors="ignore")
col1, col2, col3 = st.columns(3)
colormap = col1.selectbox("Colors", ["viridis", "plasma", "Blues", "Reds", "darkgreen"])
bg = col2.selectbox("Background", ["white", "black", "#0e1117"])
max_words = col3.slider("Max words", 30, 300, 120)
extra_stop = st.text_input("Extra stopwords (comma-separated)")
if st.button("☁️ Generate", type="primary") and text.strip():
stops = set(STOPWORDS) | {w.strip().lower() for w in extra_stop.split(",") if w.strip()}
words = re.findall(r"[a-zA-Z']{3,}", text.lower())
filtered = [w for w in words if w not in stops]
if filtered:
wc = WordCloud(
width=900, height=500, background_color=bg,
colormap=colormap, max_words=max_words, stopwords=stops,
collocations=False,
).generate(" ".join(filtered))
left, right = st.columns([0.65, 0.35])
with left:
fig, ax = plt.subplots(figsize=(9, 5))
ax.imshow(wc, interpolation="bilinear")
ax.axis("off")
st.pyplot(fig)
buf = io.BytesIO()
wc.to_image().save(buf, format="PNG")
st.download_button("⬇️ Download PNG", buf.getvalue(), "wordcloud.png", "image/png")
with right:
st.markdown("**Top 15 words**")
for word, count in Counter(filtered).most_common(15):
st.markdown(f"`{word}` — {count}")
else:
st.warning("No words left after stopword filtering!")
Step 2: Run the App
streamlit run wordcloud_app.py
Paste a few paragraphs (try your own blog posts!), generate, and tweak colors and stopwords until it looks right.
How It Works
The pipeline is text → tokens → frequencies → layout. A regex keeps alphabetic words of 3+ characters, stopwords get filtered, and WordCloud.generate() counts what remains and packs words largest-first into the canvas, rotating some for density. Setting collocations=False stops the library from gluing bigrams like “new york” into single entries — which keeps the frequency table and the cloud consistent.
The top-15 sidebar is deliberately built with collections.Counter rather than the library’s internal counts, so the numbers you see are the words you filtered — a small transparency win when you are tuning stopwords.
The download uses wc.to_image(), which hands back a PIL image you can save to a BytesIO buffer — the same export path used in the QR generator.
Common Errors & Fixes
WordCloudreceives an empty list / blank image — every token was a stopword (common with short text); thefilteredguard catches this with a friendly warning.- Font error on some systems — the library bundles a default font, but custom
font_path=values must point to a real.ttffile. - “the”, “and” still appearing — STOPWORDS covers common English only; add domain words via the extra-stopwords input (try “said, like, just”).
- Matplotlib figure has white margins — that is figure padding; pass
bbox_inches="tight", pad_inches=0toplt.savefigif you export via matplotlib instead ofto_image().
Key Concepts
- Tokenize → filter → count — the core of nearly all text analysis.
- Stopwords — filler words excluded so signal words dominate.
collocations=False— treat words individually, not as phrase pairs.- PIL export — any matplotlib/wordcloud figure becomes a downloadable image.
What to Try Next
- Render the cloud inside a shape by passing a
maskarray (a heart, a logo silhouette). - Compare two texts side by side with
st.columns— two clouds, one insight. - Feed it the OCR app’s output for an image-to-cloud pipeline.
- Add bigram mode (
collocations=True+include_numbers=False) and see how phrases change the story.
FAQ
Why do word sizes look random?
They are proportional to frequency, but layout packing adds rotation and position variance for readability. The relative sizes are exact; positions are aesthetic.
Can I use non-English text?
Yes, but pass a font_path to a font covering your script (Devanagari, Arabic, CJK) and adjust the tokenizing regex, since [a-zA-Z] excludes non-Latin letters.
Is a word cloud actually useful for analysis?
As a first glance, yes — dominant terms in seconds. Pair it with the frequency table (like this app does) and the sentiment analyzer for real insight.