Skip to content

Commit 4523f0a

Browse files
fix(pygal): address review feedback for line-retention-cohort
Attempt 1/3 - fixes based on AI review
1 parent 3442f68 commit 4523f0a

1 file changed

Lines changed: 39 additions & 8 deletions

File tree

  • plots/line-retention-cohort/implementations

plots/line-retention-cohort/implementations/pygal.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" pyplots.ai
1+
"""pyplots.ai
22
line-retention-cohort: User Retention Curve by Cohort
33
Library: pygal 3.1.0 | Python 3.14.3
44
Quality: 80/100 | Created: 2026-03-16
@@ -31,14 +31,23 @@
3131
retention.append(max(round(prev - max(drop, 0.5), 1), 5.0))
3232
retention_data[cohort] = retention
3333

34-
# Style
34+
# Style - reference line color first, then cohort colors fading from muted to vivid
35+
colors_with_opacity = (
36+
"rgba(180, 60, 60, 0.6)",
37+
"rgba(48, 105, 152, 0.45)",
38+
"rgba(232, 119, 93, 0.55)",
39+
"rgba(80, 168, 110, 0.70)",
40+
"rgba(212, 168, 67, 0.85)",
41+
"rgba(139, 107, 174, 1.0)",
42+
)
43+
3544
custom_style = Style(
3645
background="white",
3746
plot_background="white",
3847
foreground="#333",
3948
foreground_strong="#333",
4049
foreground_subtle="#cccccc",
41-
colors=("#306998", "#E8775D", "#50A86E", "#D4A843", "#8B6BAE"),
50+
colors=colors_with_opacity,
4251
title_font_size=72,
4352
label_font_size=48,
4453
major_label_font_size=42,
@@ -50,26 +59,48 @@
5059
chart = pygal.Line(
5160
width=4800,
5261
height=2700,
53-
title="line-retention-cohort · pygal · pyplots.ai",
62+
title="line-retention-cohort \u00b7 pygal \u00b7 pyplots.ai",
5463
x_title="Weeks Since Signup",
5564
y_title="Retained Users (%)",
5665
style=custom_style,
5766
show_dots=True,
5867
dots_size=6,
59-
stroke_style={"width": 5},
68+
stroke_style={"width": 3},
6069
show_y_guides=True,
6170
show_x_guides=False,
6271
legend_at_bottom=True,
6372
truncate_legend=-1,
64-
range=(0, 100),
73+
range=(0, 105),
6574
x_label_rotation=0,
75+
value_formatter=lambda x: f"{x:.0f}%" if x is not None else "",
76+
tooltip_fancy_mode=True,
77+
interpolate="cubic",
6678
)
6779

6880
chart.x_labels = [str(w) for w in weeks]
6981

70-
for cohort, params in cohorts.items():
82+
# Add reference threshold line at 20% retention
83+
chart.add(
84+
"20% Retention Threshold",
85+
[20.0] * len(weeks),
86+
stroke_style={"width": 2, "dasharray": "12, 8"},
87+
show_dots=False,
88+
dots_size=0,
89+
)
90+
91+
# Add cohorts with increasing stroke width for newer cohorts
92+
stroke_widths = [2, 3, 4, 5, 7]
93+
dot_sizes = [4, 5, 5, 6, 8]
94+
cohort_list = list(cohorts.items())
95+
96+
for i, (cohort, params) in enumerate(cohort_list):
7197
label = f"{cohort} (n={params['size']:,})"
72-
chart.add(label, retention_data[cohort])
98+
chart.add(
99+
label,
100+
[{"value": v, "label": f"Week {w}: {v:.1f}% retained"} for w, v in zip(weeks, retention_data[cohort], strict=True)],
101+
stroke_style={"width": stroke_widths[i]},
102+
dots_size=dot_sizes[i],
103+
)
73104

74105
# Save
75106
chart.render_to_file("plot.html")

0 commit comments

Comments
 (0)