{"spec_id":"ecdf-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\necdf-basic: Basic ECDF Plot\nLibrary: pygal 3.1.3 | Python 3.13.14\nQuality: 88/100 | Created: 2026-06-25\n\"\"\"\n\nimport os\nimport sys\n\n\n# Script filename shadows the installed `pygal` package when run as `python pygal.py`;\n# dropping the script directory from sys.path lets the real package resolve.\nsys.path.pop(0)\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT_PALETTE = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\n\n# 120 food-delivery times (minutes); gamma is right-skewed, realistic for\n# order-to-door durations (mean ≈ 30 min, long tail for outliers).\nnp.random.seed(42)\ndelivery_times = np.random.gamma(shape=6.0, scale=5.0, size=120)\n\n# ECDF: sorted values → cumulative proportion k/n\nsorted_values = np.sort(delivery_times)\nn = len(sorted_values)\necdf_y = np.arange(1, n + 1) / n\n\n# Step function: flat lead-in at 0, then a vertical jump + horizontal plateau\n# at each observation.\nx_lead = float(sorted_values[0]) - 2.0\nstep_points = [(x_lead, 0.0), (float(sorted_values[0]), 0.0)]\nfor i in range(n):\n    step_points.append((float(sorted_values[i]), float(ecdf_y[i])))\n    x_next = float(sorted_values[i + 1]) if i + 1 < n else float(sorted_values[-1]) + 2.0\n    step_points.append((x_next, float(ecdf_y[i])))\n\n# Quartile markers for distribution landmarks\np25 = float(np.percentile(delivery_times, 25))\np50 = float(np.percentile(delivery_times, 50))\np75 = float(np.percentile(delivery_times, 75))\n\nfont = \"DejaVu Sans, Helvetica, Arial, sans-serif\"\n\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK_SOFT,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT_PALETTE,\n    font_family=font,\n    title_font_family=font,\n    label_font_family=font,\n    major_label_font_family=font,\n    legend_font_family=font,\n    tooltip_font_family=font,\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    legend_font_size=44,\n    tooltip_font_size=32,\n    value_font_size=30,\n    stroke_opacity=1,\n    stroke_opacity_hover=1,\n    opacity=1,\n    opacity_hover=1,\n    stroke_width=3,\n)\n\nchart = pygal.XY(\n    width=3200,\n    height=1800,\n    style=custom_style,\n    title=\"ecdf-basic · python · pygal · anyplot.ai\",\n    x_title=\"Delivery Time (minutes)\",\n    y_title=\"Cumulative Proportion\",\n    show_dots=False,\n    show_x_guides=True,\n    show_y_guides=True,\n    show_legend=True,\n    range=(0, 1.05),\n    x_labels_major_count=9,\n    y_labels_major_count=6,\n    value_formatter=lambda v: f\"{v:.2f}\",\n    x_value_formatter=lambda v: f\"{v:.0f}\",\n    margin=50,\n    truncate_legend=-1,\n    js=[],\n    legend_at_bottom=True,\n    legend_at_bottom_columns=2,\n)\n\n# ECDF step function — series 1 uses brand green (#009E73)\nchart.add(\"ECDF — Delivery Times\", step_points)\n\n# Three quartile markers as separate series so each gets a distinct Imprint color\n# and its own legend entry with the exact value, making percentiles directly readable.\nchart.add(\n    f\"Q1 = {p25:.0f} min (25th percentile)\",\n    [{\"value\": (p25, 0.25), \"label\": f\"P25 = {p25:.1f} min\"}],\n    stroke=False,\n    show_dots=True,\n    dots_size=20,\n)\nchart.add(\n    f\"Median = {p50:.0f} min (50th percentile)\",\n    [{\"value\": (p50, 0.50), \"label\": f\"Median = {p50:.1f} min\"}],\n    stroke=False,\n    show_dots=True,\n    dots_size=20,\n)\nchart.add(\n    f\"Q3 = {p75:.0f} min (75th percentile)\",\n    [{\"value\": (p75, 0.75), \"label\": f\"P75 = {p75:.1f} min\"}],\n    stroke=False,\n    show_dots=True,\n    dots_size=20,\n)\n\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}