Skip to content

Commit ecaacf6

Browse files
fix(altair): address review feedback for ecdf-basic
Attempt 1/3 - fixes based on AI review
1 parent aaa262c commit ecaacf6

1 file changed

Lines changed: 25 additions & 11 deletions

File tree

  • plots/ecdf-basic/implementations/python

plots/ecdf-basic/implementations/python/altair.py

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
""" anyplot.ai
1+
"""anyplot.ai
22
ecdf-basic: Basic ECDF Plot
33
Library: altair 6.2.2 | Python 3.13.14
44
Quality: 89/100 | Updated: 2026-06-25
@@ -34,34 +34,41 @@
3434
response_times_ms = np.random.normal(loc=120, scale=35, size=250)
3535
response_times_ms = np.clip(response_times_ms, 20, None)
3636

37-
sorted_latency = np.sort(response_times_ms)
38-
cumulative_proportion = np.arange(1, len(sorted_latency) + 1) / len(sorted_latency)
39-
df = pd.DataFrame({"latency_ms": sorted_latency, "cumulative": cumulative_proportion})
37+
# Raw data frame — ECDF computed declaratively via Vega-Lite window transform
38+
df = pd.DataFrame({"latency_ms": response_times_ms})
4039

41-
# Reference values at quartiles for focal emphasis
40+
# Reference values at quartiles for focal emphasis and text annotations
4241
p25_ms = float(np.percentile(response_times_ms, 25))
4342
p50_ms = float(np.median(response_times_ms))
4443
p75_ms = float(np.percentile(response_times_ms, 75))
45-
ref_df = pd.DataFrame({"latency_ms": [p25_ms, p50_ms, p75_ms], "cumulative": [0.25, 0.50, 0.75]})
44+
ref_df = pd.DataFrame(
45+
{
46+
"latency_ms": [p25_ms, p50_ms, p75_ms],
47+
"cumulative": [0.25, 0.50, 0.75],
48+
"label": [f"~{p25_ms:.0f}ms", f"~{p50_ms:.0f}ms", f"~{p75_ms:.0f}ms"],
49+
}
50+
)
4651

4752
# Title
4853
title_str = "ecdf-basic · python · altair · anyplot.ai"
4954

50-
# ECDF step function — mark_line with step-after interpolation
55+
# ECDF step function — cume_dist() window transform computes the ECDF declaratively
56+
# in Vega-Lite without numpy preprocessing; step-after gives the correct step shape
5157
ecdf_line = (
5258
alt.Chart(df)
59+
.transform_window(ecdf="cume_dist()", sort=[alt.SortField("latency_ms")])
5360
.mark_line(interpolate="step-after", strokeWidth=3.5, color=BRAND)
5461
.encode(
5562
x=alt.X("latency_ms:Q", title="API Response Time (ms)", scale=alt.Scale(nice=True)),
5663
y=alt.Y(
57-
"cumulative:Q",
64+
"ecdf:Q",
5865
title="Cumulative Proportion",
5966
scale=alt.Scale(domain=[0, 1]),
6067
axis=alt.Axis(format=".0%", tickCount=11),
6168
),
6269
tooltip=[
6370
alt.Tooltip("latency_ms:Q", title="Latency (ms)", format=".1f"),
64-
alt.Tooltip("cumulative:Q", title="Proportion", format=".3f"),
71+
alt.Tooltip("ecdf:Q", title="Proportion", format=".3f"),
6572
],
6673
)
6774
)
@@ -93,9 +100,16 @@
93100
)
94101
)
95102

103+
# Text annotations at focal points for at-a-glance percentile reading without hover
104+
focal_labels = (
105+
alt.Chart(ref_df)
106+
.mark_text(align="left", dx=8, dy=-5, fontSize=9, color=INK_SOFT, fontWeight="bold")
107+
.encode(x="latency_ms:Q", y="cumulative:Q", text="label:N")
108+
)
109+
96110
# Compose layers and configure theme-adaptive chrome
97111
chart = (
98-
alt.layer(ecdf_line, h_rules, v_rules, focal_pts)
112+
alt.layer(ecdf_line, h_rules, v_rules, focal_pts, focal_labels)
99113
.interactive()
100114
.properties(
101115
width=620,
@@ -114,7 +128,7 @@
114128
titleFontSize=12,
115129
)
116130
.configure_axisX(grid=False)
117-
.configure_axisY(gridColor=INK, gridOpacity=0.10)
131+
.configure_axisY(gridColor=INK, gridOpacity=0.13)
118132
.configure_title(color=INK)
119133
)
120134

0 commit comments

Comments
 (0)