{"spec_id":"boxen-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nboxen-basic: Basic Boxen Plot (Letter-Value Plot)\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 86/100 | Updated: 2026-05-17\n\"\"\"\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Data - Server response times (ms) by endpoint\nnp.random.seed(42)\n\n# Generate realistic response time distributions (right-skewed)\n# Different endpoints have different performance characteristics\nn_points = 2000\n\n# Fast API endpoint (mostly quick, some slow)\nfast_api = np.concatenate(\n    [\n        np.random.exponential(scale=50, size=int(n_points * 0.85)),\n        np.random.exponential(scale=200, size=int(n_points * 0.12)),\n        np.random.exponential(scale=500, size=int(n_points * 0.03)),\n    ]\n)\n\n# Database query endpoint (moderate with variability)\ndb_query = np.concatenate(\n    [\n        np.random.exponential(scale=120, size=int(n_points * 0.7)),\n        np.random.exponential(scale=350, size=int(n_points * 0.25)),\n        np.random.exponential(scale=800, size=int(n_points * 0.05)),\n    ]\n)\n\n# File upload endpoint (slower, more variable)\nfile_upload = np.concatenate(\n    [\n        np.random.exponential(scale=200, size=int(n_points * 0.6)),\n        np.random.exponential(scale=500, size=int(n_points * 0.3)),\n        np.random.exponential(scale=1000, size=int(n_points * 0.1)),\n    ]\n)\n\n# Report generation (heavy task, wide distribution)\nreport_gen = np.concatenate(\n    [\n        np.random.exponential(scale=300, size=int(n_points * 0.5)),\n        np.random.exponential(scale=700, size=int(n_points * 0.35)),\n        np.random.exponential(scale=1500, size=int(n_points * 0.15)),\n    ]\n)\n\ncategories = [\"Fast API\", \"DB Query\", \"File Upload\", \"Report Gen\"]\ndata = [fast_api, db_query, file_upload, report_gen]\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# Color palette - nested boxes use progressively darker shades\nn_levels = 6\n\n# Generate colors from light (outer) to dark (inner) for Python Blue\ncolors = []\nfor i in range(n_levels):\n    # Interpolate from very light blue to Python Blue\n    factor = 0.2 + (i / (n_levels - 1)) * 0.8\n    r = int(48 * factor + 230 * (1 - factor))\n    g = int(105 * factor + 240 * (1 - factor))\n    b = int(152 * factor + 255 * (1 - factor))\n    colors.append(f\"#{r:02x}{g:02x}{b:02x}\")\n\n# Width parameters - each level gets progressively narrower\nbase_width = 0.75\nwidth_decay = 0.82  # Each inner box is 82% width of outer\npositions = range(1, len(categories) + 1)\n\n# Draw boxen plots for each category\nfor pos, arr in zip(positions, data, strict=True):\n    # Compute letter values (quantiles for boxen plot)\n    # Level 0: 25-75% (IQR), Level 1: 12.5-87.5%, etc.\n    quantile_pairs = []\n    for i in range(n_levels):\n        lower_p = 0.5 ** (i + 2)  # 0.25, 0.125, 0.0625, ...\n        upper_p = 1 - lower_p  # 0.75, 0.875, 0.9375, ...\n        lower_val = np.percentile(arr, lower_p * 100)\n        upper_val = np.percentile(arr, upper_p * 100)\n        quantile_pairs.append((lower_val, upper_val))\n\n    median = np.median(arr)\n\n    # Draw boxes from outermost (widest) to innermost (narrowest)\n    for i in range(n_levels - 1, -1, -1):\n        lower_val, upper_val = quantile_pairs[i]\n        width = base_width * (width_decay**i)\n\n        # Draw rectangle for this quantile level\n        rect = mpatches.FancyBboxPatch(\n            (pos - width / 2, lower_val),\n            width,\n            upper_val - lower_val,\n            boxstyle=mpatches.BoxStyle(\"Round\", pad=0.02),\n            facecolor=colors[i],\n            edgecolor=\"#1a3d5c\",\n            linewidth=2,\n            zorder=5 + i,\n        )\n        ax.add_patch(rect)\n\n    # Draw median line (bright yellow for visibility)\n    median_width = base_width * (width_decay ** (n_levels - 1)) * 0.8\n    ax.hlines(median, pos - median_width / 2, pos + median_width / 2, colors=\"#FFD43B\", linewidth=5, zorder=20)\n\n    # Plot outliers beyond the outermost quantile\n    outer_lower, outer_upper = quantile_pairs[-1]\n    outliers = arr[(arr < outer_lower) | (arr > outer_upper)]\n    if len(outliers) > 0:\n        # Sample outliers if too many\n        if len(outliers) > 80:\n            outlier_sample = np.random.choice(outliers, 80, replace=False)\n        else:\n            outlier_sample = outliers\n        ax.scatter([pos] * len(outlier_sample), outlier_sample, color=\"#1a3d5c\", s=40, alpha=0.6, zorder=4, marker=\"o\")\n\n# Labels and styling\nax.set_xlabel(\"API Endpoint\", fontsize=20)\nax.set_ylabel(\"Response Time (ms)\", fontsize=20)\nax.set_title(\"boxen-basic · matplotlib · pyplots.ai\", fontsize=24)\nax.set_xticks(list(positions))\nax.set_xticklabels(categories, fontsize=16)\nax.tick_params(axis=\"y\", labelsize=16)\nax.grid(True, alpha=0.3, linestyle=\"--\", axis=\"y\")\n\n# Set y-axis to start at 0\nax.set_ylim(bottom=0)\n\n# Create legend showing quantile coverage\nlegend_labels = [\"25-75% (IQR)\", \"12.5-87.5%\", \"6.25-93.75%\", \"3.125-96.875%\", \"1.56-98.44%\", \"0.78-99.22%\"]\nlegend_patches = []\nfor color, label in zip(colors, legend_labels, strict=True):\n    patch = mpatches.Patch(facecolor=color, edgecolor=\"#1a3d5c\", linewidth=1, label=label)\n    legend_patches.append(patch)\n\n# Add median and outlier markers to legend\nmedian_line = plt.Line2D([0], [0], color=\"#FFD43B\", linewidth=5, label=\"Median\")\nlegend_patches.insert(0, median_line)\noutlier_marker = plt.Line2D(\n    [0],\n    [0],\n    marker=\"o\",\n    color=\"w\",\n    markerfacecolor=\"#1a3d5c\",\n    markersize=8,\n    alpha=0.6,\n    label=\"Outliers\",\n    linestyle=\"None\",\n)\nlegend_patches.append(outlier_marker)\n\nax.legend(\n    handles=legend_patches, loc=\"upper right\", fontsize=13, title=\"Letter Values\", title_fontsize=15, framealpha=0.95\n)\n\nplt.tight_layout()\nplt.savefig(\"plot.png\", dpi=300, bbox_inches=\"tight\")\n"}