{"spec_id":"ecdf-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\necdf-basic: Basic ECDF Plot\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-06-25\n\"\"\"\n\nimport os\nimport sys\n\nimport numpy as np\nimport pandas as pd\n\n\n# Avoid shadowing the plotnine library when this file is run directly\n_cwd = os.getcwd()\nsys.path = [p for p in sys.path if os.path.abspath(p) != _cwd]\n\nfrom plotnine import (\n    aes,\n    annotate,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_hline,\n    geom_vline,\n    ggplot,\n    ggsave,\n    labs,\n    scale_x_continuous,\n    scale_y_continuous,\n    stat_ecdf,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme tokens (Imprint palette)\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nBRAND = \"#009E73\"  # Imprint palette position 1\n\n# Data: test scores — normal distribution\nnp.random.seed(42)\nscores = np.random.randn(200) * 15 + 50\nq1 = float(np.percentile(scores, 25))\nmedian_score = float(np.median(scores))\nq3 = float(np.percentile(scores, 75))\n\ndf = pd.DataFrame({\"score\": scores})\n\ntitle = \"ecdf-basic · python · plotnine · anyplot.ai\"\n\n# Plot — stat_ecdf computes ECDF internally via plotnine's stat layer\nplot = (\n    ggplot(df, aes(x=\"score\"))\n    # IQR shaded band — highlights the interquartile range (middle 50%)\n    + annotate(\"rect\", xmin=q1, xmax=q3, ymin=0.0, ymax=1.0, fill=BRAND, alpha=0.06)\n    # Quartile reference crosshairs (Q1, median, Q3)\n    + geom_hline(yintercept=0.25, color=INK_SOFT, size=0.5, linetype=\"dotted\", alpha=0.55)\n    + geom_hline(yintercept=0.50, color=INK_SOFT, size=0.6, linetype=\"dotted\", alpha=0.70)\n    + geom_hline(yintercept=0.75, color=INK_SOFT, size=0.5, linetype=\"dotted\", alpha=0.55)\n    + geom_vline(xintercept=q1, color=INK_SOFT, size=0.5, linetype=\"dotted\", alpha=0.55)\n    + geom_vline(xintercept=median_score, color=INK_SOFT, size=0.6, linetype=\"dotted\", alpha=0.70)\n    + geom_vline(xintercept=q3, color=INK_SOFT, size=0.5, linetype=\"dotted\", alpha=0.55)\n    # ECDF step line — rendered on top of reference elements\n    + stat_ecdf(geom=\"step\", color=BRAND, size=1.1)\n    # Quartile annotations — teach readers how to extract percentile information\n    + annotate(\"text\", x=q1 + 1.5, y=0.16, label=f\"Q1: {q1:.1f}\", color=INK_SOFT, size=3.5, ha=\"left\")\n    + annotate(\n        \"text\", x=median_score + 1.5, y=0.08, label=f\"Median: {median_score:.1f}\", color=INK_SOFT, size=4.0, ha=\"left\"\n    )\n    + annotate(\"text\", x=q3 + 1.5, y=0.80, label=f\"Q3: {q3:.1f}\", color=INK_SOFT, size=3.5, ha=\"left\")\n    + labs(x=\"Test Score (points)\", y=\"Cumulative Proportion\", title=title)\n    + scale_x_continuous(expand=(0.01, 0))\n    + scale_y_continuous(limits=(0, 1), breaks=np.arange(0, 1.1, 0.1), expand=(0.01, 0))\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_border=element_blank(),\n        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.15),\n        panel_grid_minor=element_blank(),\n        axis_line=element_line(color=INK_SOFT, size=0.6),\n        axis_ticks=element_line(color=INK_SOFT, size=0.5),\n        text=element_text(color=INK, size=7),\n        plot_title=element_text(color=INK, size=12, weight=\"medium\", ha=\"left\"),\n        axis_title=element_text(color=INK, size=10),\n        axis_text=element_text(color=INK_SOFT, size=8),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_text=element_text(color=INK_SOFT, size=8),\n        legend_title=element_text(color=INK, size=8),\n    )\n)\n\nggsave(plot, filename=f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5)\n"}