{"spec_id":"ecdf-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\necdf-basic: Basic ECDF Plot\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 88/100 | Updated: 2026-06-25\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove the script's own directory from sys.path so this file doesn't shadow\n# the installed plotly package (script is named plotly.py).\nsys.path = [p for p in sys.path if p not in (\"\", os.path.dirname(os.path.abspath(__file__)))]\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\nBRAND = \"#009E73\"  # Imprint palette position 1 — always first series\nANYPLOT_AMBER = \"#DDCC77\"  # annotation accent\n\n# Data: HTTP API response latencies (ms) for 400 requests to a web service\nnp.random.seed(42)\nn_requests = 400\n# Lognormal distribution models real-world latency well (long right tail)\nlatency_ms = np.random.lognormal(mean=4.8, sigma=0.5, size=n_requests)\n\n# ECDF\nsorted_latency = np.sort(latency_ms)\ncumulative_proportion = np.arange(1, n_requests + 1) / n_requests\n\n# Key percentiles\np50 = np.percentile(sorted_latency, 50)\np90 = np.percentile(sorted_latency, 90)\np99 = np.percentile(sorted_latency, 99)\nx_max = np.percentile(sorted_latency, 99.5)\n\n# Plot\nfig = go.Figure()\n\n# ECDF line\nfig.add_trace(\n    go.Scatter(\n        x=sorted_latency,\n        y=cumulative_proportion,\n        mode=\"lines\",\n        line={\"color\": BRAND, \"width\": 2.5, \"shape\": \"hv\"},\n        hovertemplate=\"<b>Latency</b>: %{x:.1f} ms<br><b>Cumulative</b>: %{y:.1%}<extra></extra>\",\n        showlegend=False,\n    )\n)\n\n# Percentile reference lines (dashed horizontal)\nfor pct_val, pct_label, y_pct in [(p50, \"P50\", 0.50), (p90, \"P90\", 0.90), (p99, \"P99\", 0.99)]:\n    fig.add_shape(\n        type=\"line\",\n        x0=0,\n        x1=pct_val,\n        y0=y_pct,\n        y1=y_pct,\n        line={\"color\": INK_SOFT, \"width\": 1, \"dash\": \"dot\"},\n        layer=\"below\",\n    )\n    fig.add_shape(\n        type=\"line\",\n        x0=pct_val,\n        x1=pct_val,\n        y0=0,\n        y1=y_pct,\n        line={\"color\": INK_SOFT, \"width\": 1, \"dash\": \"dot\"},\n        layer=\"below\",\n    )\n    fig.add_annotation(\n        x=pct_val,\n        y=y_pct,\n        text=f\"<b>{pct_label}</b> {pct_val:.0f} ms\",\n        showarrow=False,\n        xanchor=\"left\",\n        yanchor=\"bottom\",\n        xshift=6,\n        yshift=4,\n        font={\"size\": 10, \"color\": INK_SOFT},\n    )\n\n# Style\ntitle_text = \"HTTP API Latency · ecdf-basic · python · plotly · anyplot.ai\"\nfig.update_layout(\n    autosize=False,\n    title={\"text\": title_text, \"font\": {\"size\": 16, \"color\": INK}, \"x\": 0.5, \"xanchor\": \"center\", \"y\": 0.95},\n    xaxis={\n        \"title\": {\"text\": \"Response Time (ms)\", \"font\": {\"size\": 12, \"color\": INK}, \"standoff\": 12},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n        \"showline\": False,\n        \"mirror\": False,\n        \"range\": [0, x_max],\n    },\n    yaxis={\n        \"title\": {\"text\": \"Cumulative Proportion of Requests\", \"font\": {\"size\": 12, \"color\": INK}, \"standoff\": 12},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n        \"showline\": False,\n        \"mirror\": False,\n        \"range\": [0, 1.02],\n        \"tickformat\": \".0%\",\n        \"dtick\": 0.1,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK, \"family\": \"Inter, Helvetica Neue, Arial, sans-serif\"},\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 60},\n    hovermode=\"x unified\",\n    hoverlabel={\"bgcolor\": ELEVATED_BG, \"bordercolor\": INK_SOFT, \"font\": {\"color\": INK, \"size\": 12}, \"align\": \"left\"},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(\n    f\"plot-{THEME}.html\",\n    include_plotlyjs=\"cdn\",\n    config={\n        \"displaylogo\": False,\n        \"modeBarButtonsToRemove\": [\"lasso2d\", \"select2d\", \"autoScale2d\"],\n        \"toImageButtonOptions\": {\"format\": \"png\", \"filename\": \"ecdf-basic-plotly\"},\n    },\n)\n"}