{"spec_id":"boxen-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nboxen-basic: Basic Boxen Plot (Letter-Value Plot)\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-17\n\"\"\"\n\nimport os\nimport sys\n\n\n# Prioritize venv's site-packages over current directory\nif sys.prefix not in sys.path:\n    import site\n\n    site_packages = site.getsitepackages()\n    if isinstance(site_packages, list):\n        sys.path = site_packages + sys.path\n    else:\n        sys.path.insert(0, site_packages)\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.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\nBRAND = \"#009E73\"\n\n# Data - Server response times by endpoint (large dataset for boxen plot)\nnp.random.seed(42)\n\nendpoints = [\"API Gateway\", \"Auth Service\", \"Data Query\", \"File Upload\"]\nn_points = 5000\n\n# Generate different distributions for each endpoint\ndata = {\n    \"API Gateway\": np.concatenate(\n        [\n            np.random.lognormal(mean=4, sigma=0.5, size=int(n_points * 0.9)),\n            np.random.uniform(200, 500, size=int(n_points * 0.1)),\n        ]\n    ),\n    \"Auth Service\": np.random.exponential(scale=30, size=n_points) + 10,\n    \"Data Query\": np.concatenate(\n        [\n            np.random.normal(loc=100, scale=20, size=int(n_points * 0.7)),\n            np.random.normal(loc=250, scale=30, size=int(n_points * 0.3)),\n        ]\n    ),\n    \"File Upload\": np.concatenate(\n        [\n            np.random.gamma(shape=2, scale=50, size=int(n_points * 0.85)),\n            np.random.uniform(400, 800, size=int(n_points * 0.15)),\n        ]\n    ),\n}\n\n# Colors for quantile levels - theme-adaptive brand green with varying opacity\ncolors = [\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 1.0)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.85)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.7)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.55)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.4)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.3)\",\n    f\"rgba({int(BRAND[1:3], 16)}, {int(BRAND[3:5], 16)}, {int(BRAND[5:7], 16)}, 0.2)\",\n]\n\nfig = go.Figure()\n\nbox_width_base = 0.7\npositions = list(range(len(endpoints)))\nn_levels = 7  # Number of letter value levels\n\nfor idx, endpoint in enumerate(endpoints):\n    pos = positions[idx]\n    values = data[endpoint]\n    n = len(values)\n    sorted_vals = np.sort(values)\n    median = np.median(values)\n\n    # Compute letter values (quantiles at 1/2, 1/4, 1/8, 1/16, etc.)\n    letter_values = []\n    for i in range(n_levels):\n        depth = 2 ** (i + 1)\n        lower_idx = max(0, min(int(n / depth), n - 1))\n        upper_idx = max(0, min(int(n - n / depth), n - 1))\n        letter_values.append((sorted_vals[lower_idx], sorted_vals[upper_idx]))\n\n    # Draw boxes from outermost (widest, lightest) to innermost (narrowest, darkest)\n    for i in range(n_levels - 1, -1, -1):\n        lower, upper = letter_values[i]\n        width = box_width_base * (1 - i * 0.15)  # Increased from 0.10 to 0.15 for more pronounced decrease\n\n        fig.add_shape(\n            type=\"rect\",\n            x0=pos - width / 2,\n            x1=pos + width / 2,\n            y0=lower,\n            y1=upper,\n            fillcolor=colors[i],\n            line={\"color\": INK_SOFT, \"width\": 1.5},\n            layer=\"below\",\n        )\n\n    # Add median line\n    fig.add_shape(\n        type=\"line\",\n        x0=pos - box_width_base / 2,\n        x1=pos + box_width_base / 2,\n        y0=median,\n        y1=median,\n        line={\"color\": INK, \"width\": 5},\n    )\n\n    # Find and plot outliers (beyond the outermost letter value)\n    outer_lower, outer_upper = letter_values[-1]\n    outliers = values[(values < outer_lower) | (values > outer_upper)]\n\n    if len(outliers) > 0:\n        outlier_sample = outliers if len(outliers) <= 100 else np.random.choice(outliers, 100, replace=False)\n        jitter = np.random.uniform(-0.08, 0.08, size=len(outlier_sample))\n\n        fig.add_trace(\n            go.Scatter(\n                x=pos + jitter,\n                y=outlier_sample,\n                mode=\"markers\",\n                marker={\"color\": BRAND, \"size\": 11, \"opacity\": 0.7},\n                showlegend=False,\n                hovertemplate=\"Response: %{y:.0f}ms<extra></extra>\",\n            )\n        )\n\n# Add legend entries for quantile levels\nquantile_labels = [\"50% (IQR)\", \"75%\", \"87.5%\", \"93.75%\", \"96.9%\", \"98.4%\", \"99.2%\"]\nfor i, label in enumerate(quantile_labels):\n    fig.add_trace(\n        go.Scatter(\n            x=[None],\n            y=[None],\n            mode=\"markers\",\n            marker={\"size\": 20, \"color\": colors[i], \"symbol\": \"square\", \"line\": {\"color\": INK_SOFT, \"width\": 1}},\n            name=label,\n            showlegend=True,\n        )\n    )\n\n# Add median legend entry\nfig.add_trace(\n    go.Scatter(x=[None], y=[None], mode=\"lines\", line={\"color\": INK, \"width\": 5}, name=\"Median\", showlegend=True)\n)\n\n# Layout\nfig.update_layout(\n    title={\n        \"text\": \"boxen-basic · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Server Endpoint\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"tickvals\": positions,\n        \"ticktext\": endpoints,\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Response Time (ms)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    legend={\n        \"title\": {\"text\": \"Quantile Level\", \"font\": {\"size\": 20, \"color\": INK}},\n        \"font\": {\"size\": 18, \"color\": INK_SOFT},\n        \"x\": 0.98,\n        \"y\": 0.5,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"middle\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    margin={\"l\": 120, \"r\": 220, \"t\": 100, \"b\": 100},\n)\n\n# Save as PNG and HTML\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}