Skip to content

Commit d7f30db

Browse files
feat(matplotlib): implement streamgraph-basic (#5697)
## Implementation: `streamgraph-basic` - python/matplotlib Implements the **python/matplotlib** version of `streamgraph-basic`. **File:** `plots/streamgraph-basic/implementations/python/matplotlib.py` **Parent Issue:** #856 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25355850299)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 7c27b4f commit d7f30db

2 files changed

Lines changed: 218 additions & 185 deletions

File tree

Lines changed: 39 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
streamgraph-basic: Basic Stream Graph
3-
Library: matplotlib 3.10.8 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: matplotlib 3.10.9 | Python 3.13.13
4+
Quality: 88/100 | Updated: 2026-05-05
55
"""
66

7+
import os
8+
79
import matplotlib.pyplot as plt
810
import numpy as np
11+
from scipy.interpolate import make_interp_spline
12+
13+
14+
THEME = os.getenv("ANYPLOT_THEME", "light")
15+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
16+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
17+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
18+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
919

20+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9"]
1021

11-
# Data - Monthly streaming hours by music genre over two years
1222
np.random.seed(42)
1323

14-
# 24 months of data
1524
months = np.arange(24)
1625
month_labels = [
1726
"Jan'23",
@@ -40,68 +49,49 @@
4049
"Dec'24",
4150
]
4251

43-
# Generate realistic genre streaming data with trends
44-
# Pop - consistently high, slight growth
52+
# Monthly streaming hours by music genre — diverse trend patterns
4553
pop = 50 + 10 * np.sin(months / 6) + np.random.randn(24) * 3 + months * 0.3
46-
47-
# Rock - stable with seasonal variation
4854
rock = 35 + 8 * np.cos(months / 4) + np.random.randn(24) * 2
49-
50-
# Hip-Hop - growing trend
5155
hiphop = 25 + months * 0.8 + 5 * np.sin(months / 3) + np.random.randn(24) * 3
52-
53-
# Electronic - summer peaks
5456
electronic = 20 + 15 * np.sin((months - 3) / 6 * np.pi) + np.random.randn(24) * 2
55-
56-
# Jazz - steady, slight decline
5757
jazz = 18 - months * 0.15 + 4 * np.cos(months / 5) + np.random.randn(24) * 1.5
58+
classical = 15 + 8 * np.cos(months / 6 * np.pi) + np.random.randn(24) * 1.5
5859

59-
# Classical - winter peaks
60-
classical = 15 + 8 * np.cos((months) / 6 * np.pi) + np.random.randn(24) * 1.5
61-
62-
# Ensure all values are positive
63-
pop = np.maximum(pop, 5)
64-
rock = np.maximum(rock, 5)
65-
hiphop = np.maximum(hiphop, 5)
66-
electronic = np.maximum(electronic, 5)
67-
jazz = np.maximum(jazz, 5)
68-
classical = np.maximum(classical, 5)
60+
data_raw = [pop, rock, hiphop, electronic, jazz, classical]
61+
for arr in data_raw:
62+
np.maximum(arr, 5, out=arr)
6963

70-
# Stack the data
71-
data = np.vstack([pop, rock, hiphop, electronic, jazz, classical])
7264
categories = ["Pop", "Rock", "Hip-Hop", "Electronic", "Jazz", "Classical"]
7365

74-
# Colors - starting with Python Blue/Yellow, then colorblind-safe palette
75-
colors = ["#306998", "#FFD43B", "#E07A5F", "#81B29A", "#F2CC8F", "#3D405B"]
76-
77-
# Create plot (4800x2700 px)
78-
fig, ax = plt.subplots(figsize=(16, 9))
66+
# Cubic spline interpolation → smooth, flowing curves
67+
months_fine = np.linspace(0, 23, 300)
68+
data_smooth = np.array([np.maximum(make_interp_spline(months, series, k=3)(months_fine), 1.0) for series in data_raw])
7969

80-
# Create streamgraph with symmetric baseline (wiggle for stream-like appearance)
81-
ax.stackplot(months, data, labels=categories, colors=colors, baseline="wiggle", alpha=0.85)
70+
fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)
71+
ax.set_facecolor(PAGE_BG)
8272

83-
# Styling
84-
ax.set_xlabel("Month", fontsize=20)
85-
ax.set_title("streamgraph-basic · matplotlib · pyplots.ai", fontsize=24)
73+
ax.stackplot(months_fine, data_smooth, labels=categories, colors=OKABE_ITO, baseline="wiggle", alpha=0.85)
8674

87-
# X-axis labels
88-
ax.set_xticks(months[::3])
89-
ax.set_xticklabels([month_labels[i] for i in range(0, 24, 3)], fontsize=16)
90-
ax.tick_params(axis="y", labelsize=16)
75+
ax.set_xlabel("Month (Jan 2023 – Dec 2024)", fontsize=20, color=INK)
76+
ax.set_title("streamgraph-basic · matplotlib · anyplot.ai", fontsize=24, color=INK, fontweight="medium")
9177

92-
# Remove y-axis ticks for cleaner stream appearance (values are relative)
78+
tick_positions = list(range(0, 24, 3))
79+
ax.set_xticks(tick_positions)
80+
ax.set_xticklabels([month_labels[i] for i in tick_positions], fontsize=16)
81+
ax.tick_params(axis="x", colors=INK_SOFT, labelcolor=INK_SOFT)
9382
ax.set_yticks([])
9483

95-
# Add legend
96-
ax.legend(loc="upper left", fontsize=16, framealpha=0.9)
97-
98-
# Subtle styling - remove top and right spines
9984
ax.spines["top"].set_visible(False)
10085
ax.spines["right"].set_visible(False)
10186
ax.spines["left"].set_visible(False)
87+
ax.spines["bottom"].set_color(INK_SOFT)
88+
89+
ax.set_xlim(months_fine[0], months_fine[-1])
10290

103-
# Set x limits to remove padding
104-
ax.set_xlim(0, 23)
91+
leg = ax.legend(loc="upper left", fontsize=16, framealpha=0.9)
92+
leg.get_frame().set_facecolor(ELEVATED_BG)
93+
leg.get_frame().set_edgecolor(INK_SOFT)
94+
plt.setp(leg.get_texts(), color=INK_SOFT)
10595

10696
plt.tight_layout()
107-
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
97+
plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG)

0 commit comments

Comments
 (0)