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
.txt/.md file.Prerequisites
pip install streamlit wordcloud matplotlibStep 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.pyPaste 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
filtered guard catches this with a friendly warning.font_path= values must point to a real .ttf file.bbox_inches="tight", pad_inches=0 to plt.savefig if you export via matplotlib instead of to_image().Key Concepts
What to Try Next
mask array (a heart, a logo silhouette).st.columns — two clouds, one insight.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.