Project 18: Sentiment Mood Ring 💭¶

Difficulty: 🟡 Intermediate

Run cells top to bottom. Each step builds on the previous one and saves real files under outputs/sentiment_mood_ring/.

← Back to index

Description¶

Analyze text sentiment with a lightweight lexicon scorer and visualize the mood as a color ring.

Libraries & Modules¶

  • Built-in: re, str
  • matplotlib.pyplot — polar plot mood ring
  • Optional upgrade: textblob for NLP

Python Concepts You'll Practice¶

Text processing, scoring algorithms, polar plots

🎛️ Parameter Variations¶

  • TEXT — reviews, tweets, journal entries
  • Extend POSITIVE / NEGATIVE word lists
  • RING_SEGMENTS — visual granularity
In [1]:
# Install dependencies for this project (safe to re-run)
import sys
!{sys.executable} -m pip install pillow numpy matplotlib wordcloud qrcode[pil] python-barcode fpdf2 jinja2 folium plotly pandas scipy ipywidgets -q
Skipping pip install (already installed)
In [2]:
# Interactive Jupyter setup — run this cell first
%matplotlib inline

from pathlib import Path
from IPython.display import display, Image as IPImage, HTML, Markdown, Audio, IFrame

OUTPUT_DIR = Path("outputs") / "sentiment_mood_ring"
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
print(f"✅ Outputs folder: {OUTPUT_DIR.resolve()}")
✅ Outputs folder: C:\Users\Hansel Yan\Projects\CodeItAll\outputs\sentiment_mood_ring

Step 1 — Lexicon-based sentiment scorer¶

In [3]:
import re

# 🎛️ TWEAK THESE
TEXT = """
I absolutely love learning Python! The projects are creative and fun.
Sometimes debugging is frustrating, but the results are amazing and rewarding.
CodeItAll makes programming feel approachable and exciting.
"""

POSITIVE = {"love", "creative", "fun", "amazing", "rewarding", "approachable", "exciting", "great", "good", "happy", "excellent"}
NEGATIVE = {"frustrating", "bad", "hate", "terrible", "boring", "difficult", "awful", "sad", "angry", "worst"}

def score_sentiment(text):
    words = re.findall(r"[a-zA-Z']+", text.lower())
    pos = sum(1 for w in words if w in POSITIVE)
    neg = sum(1 for w in words if w in NEGATIVE)
    total = pos + neg or 1
    compound = (pos - neg) / total  # -1 to 1
    label = "Positive 😊" if compound > 0.15 else "Negative 😔" if compound < -0.15 else "Neutral 😐"
    return {"positive": pos, "negative": neg, "compound": compound, "label": label, "word_count": len(words)}

result = score_sentiment(TEXT)
print(result)
print(f"Mood: {result['label']}")
{'positive': 7, 'negative': 1, 'compound': 0.75, 'label': 'Positive 😊', 'word_count': 29}
Mood: Positive 😊

Step 2 — Mood ring visualization¶

In [4]:
import numpy as np
import matplotlib.pyplot as plt

# 🎛️ TWEAK THESE
RING_SEGMENTS = 36

compound = result["compound"]
# Map compound (-1..1) to hue: red → yellow → green
mood_color = plt.cm.RdYlGn((compound + 1) / 2)

fig, ax = plt.subplots(subplot_kw={"projection": "polar"}, figsize=(6, 6))
theta = np.linspace(0, 2 * np.pi, RING_SEGMENTS, endpoint=False)
radii = np.ones(RING_SEGMENTS)
colors = [plt.cm.RdYlGn((compound + 1) / 2 + 0.05 * np.sin(i)) for i in range(RING_SEGMENTS)]
ax.bar(theta, radii, width=2*np.pi/RING_SEGMENTS, bottom=0.5, color=colors, edgecolor="white", linewidth=0.5)
ax.set_ylim(0, 1.5)
ax.axis("off")
ax.set_title(f"Sentiment Mood Ring\n{result['label']} (score: {compound:+.2f})", fontsize=13, pad=20)

out = OUTPUT_DIR / "sentiment_mood_ring.png"
fig.savefig(out, dpi=120, bbox_inches="tight")
plt.show()
print(f"Saved to {out}")
No description has been provided for this image
Saved to outputs\sentiment_mood_ring\sentiment_mood_ring.png

✅ Project complete¶

Check your output folder: outputs/sentiment_mood_ring/

Next: Project 19: GeoMap Storyteller · Index