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/.
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:
textblobfor NLP
Python Concepts You'll Practice¶
Text processing, scoring algorithms, polar plots
🎛️ Parameter Variations¶
TEXT— reviews, tweets, journal entries- Extend
POSITIVE/NEGATIVEword 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}")
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