DevelopmentMarch 31, 20254 min read

Word Cloud Generator using Python and Streamlit

Turn any text into a word cloud with Python and Streamlit — custom colors, shapes, and stopword filtering with instant PNG download.

Galvan

Galvan

Founder & Creator

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/.md file.
  • 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:
  • code
    pip install streamlit wordcloud matplotlib

    Step 1: Create the Script

    Save as wordcloud_app.py:

    code
    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

    code
    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

  • `WordCloud` receives an empty list / blank image — every token was a stopword (common with short text); the filtered guard 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 .ttf file.
  • "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=0 to plt.savefig if you export via matplotlib instead of to_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 mask array (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.