{"spec_id":"box-grouped","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nbox-grouped: Grouped Box Plot\nLibrary: plotnine 0.15.8 | Python 3.13.15\nQuality: 92/100 | Updated: 2026-08-18\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_boxplot,\n    geom_jitter,\n    ggplot,\n    ggsave,\n    labs,\n    position_dodge2,\n    position_jitterdodge,\n    scale_color_manual,\n    scale_fill_manual,\n    theme,\n    theme_minimal,\n)\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\"\n\n# Imprint palette (first series always #009E73)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data: Employee performance scores by department and experience level\nnp.random.seed(42)\n\ndepartments = [\"Engineering\", \"Marketing\", \"Sales\", \"Support\"]\nexperience_levels = [\"Junior\", \"Mid-Level\", \"Senior\"]\n\ndata = []\nfor dept in departments:\n    for exp in experience_levels:\n        # Create realistic performance distributions that vary by dept and experience\n        n = 40\n        if dept == \"Engineering\":\n            base = 70 if exp == \"Junior\" else 78 if exp == \"Mid-Level\" else 85\n            spread = 12 if exp == \"Junior\" else 10 if exp == \"Mid-Level\" else 8\n        elif dept == \"Marketing\":\n            base = 68 if exp == \"Junior\" else 75 if exp == \"Mid-Level\" else 82\n            spread = 14 if exp == \"Junior\" else 11 if exp == \"Mid-Level\" else 9\n        elif dept == \"Sales\":\n            base = 65 if exp == \"Junior\" else 77 if exp == \"Mid-Level\" else 88\n            spread = 15 if exp == \"Junior\" else 12 if exp == \"Mid-Level\" else 7\n        else:  # Support\n            base = 72 if exp == \"Junior\" else 76 if exp == \"Mid-Level\" else 80\n            spread = 10 if exp == \"Junior\" else 9 if exp == \"Mid-Level\" else 8\n\n        values = np.random.normal(base, spread, n)\n        # Add some outliers\n        if exp == \"Senior\" and dept == \"Sales\":\n            values = np.append(values, [55, 98])\n        if exp == \"Junior\" and dept == \"Engineering\":\n            values = np.append(values, [42, 95])\n\n        for v in values:\n            data.append({\"Department\": dept, \"Experience\": exp, \"Score\": v})\n\ndf = pd.DataFrame(data)\n\n# Order experience levels properly\ndf[\"Experience\"] = pd.Categorical(df[\"Experience\"], categories=experience_levels, ordered=True)\n\n# Create theme\nanyplot_theme = theme(\n    plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n    panel_background=element_rect(fill=PAGE_BG),\n    panel_grid_major_x=element_blank(),\n    panel_grid_major_y=element_line(color=INK, size=0.3, alpha=0.12),\n    panel_grid_minor=element_blank(),\n    panel_border=element_blank(),\n    axis_line=element_line(color=INK_SOFT, size=0.6),\n    axis_title=element_text(color=INK, size=10),\n    axis_text=element_text(color=INK_SOFT, size=8),\n    axis_ticks=element_line(color=INK_SOFT, size=0.4),\n    plot_title=element_text(color=INK, size=12, weight=\"bold\"),\n    legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT, size=0.4),\n    legend_text=element_text(color=INK_SOFT, size=8),\n    legend_title=element_text(color=INK, size=9),\n    figure_size=(8, 4.5),\n)\n\n# Grouped box plot: dodged boxes per experience level, jittered raw scores\n# underneath for distributional texture (design refinement over library defaults)\nplot = (\n    ggplot(df, aes(x=\"Department\", y=\"Score\"))\n    + geom_jitter(\n        aes(color=\"Experience\"),\n        position=position_jitterdodge(jitter_width=0.15, dodge_width=0.7),\n        size=0.8,\n        alpha=0.28,\n        show_legend=False,\n    )\n    + geom_boxplot(\n        aes(fill=\"Experience\"),\n        position=position_dodge2(preserve=\"single\", padding=0.1),\n        width=0.7,\n        color=INK,\n        size=0.6,\n        alpha=0.88,\n        outlier_size=2.2,\n        outlier_alpha=0.8,\n        outlier_color=INK_SOFT,\n    )\n    + scale_fill_manual(values=IMPRINT)\n    + scale_color_manual(values=IMPRINT)\n    + labs(\n        x=\"Department\",\n        y=\"Performance Score (0-100)\",\n        title=\"box-grouped · plotnine · anyplot.ai\",\n        fill=\"Experience Level\",\n    )\n    + theme_minimal()\n    + anyplot_theme\n)\n\n# Save\nggsave(plot, filename=f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\")\n"}