{"spec_id":"boxen-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nboxen-basic: Basic Boxen Plot (Letter-Value Plot)\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 61/100 | Created: 2026-05-17\n\"\"\"\n\nimport importlib\nimport os\nimport sys\n\nimport numpy as np\n\n\nscript_dir = sys.path[0]\nsys.path.pop(0)\npygal = importlib.import_module(\"pygal\")\nStyle = importlib.import_module(\"pygal.style\").Style\nsys.path.insert(0, script_dir)\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\nnp.random.seed(42)\nendpoints = [\"API-Auth\", \"API-Search\", \"API-Report\", \"API-Download\"]\n\napi_auth = np.concatenate([np.random.gamma(shape=2, scale=20, size=3500), np.random.uniform(200, 1000, size=200)])\n\napi_search = np.concatenate([np.random.gamma(shape=1.5, scale=30, size=3500), np.random.uniform(300, 1200, size=200)])\n\napi_report = np.concatenate([np.random.gamma(shape=2.5, scale=25, size=3500), np.random.uniform(250, 900, size=200)])\n\napi_download = np.concatenate([np.random.gamma(shape=2, scale=35, size=3500), np.random.uniform(400, 1500, size=200)])\n\ndatasets = [api_auth, api_search, api_report, api_download]\n\n\ndef get_letter_values(data):\n    \"\"\"Calculate letter values at multiple quantile levels\"\"\"\n    quantiles = {\n        \"sixteenths\": (np.percentile(data, 6.25), np.percentile(data, 93.75)),\n        \"eighths\": (np.percentile(data, 12.5), np.percentile(data, 87.5)),\n        \"quartiles\": (np.percentile(data, 25), np.percentile(data, 75)),\n        \"median\": (np.percentile(data, 50), np.percentile(data, 50)),\n    }\n    return quantiles\n\n\ndef get_outliers(data):\n    \"\"\"Get points beyond sixteenths\"\"\"\n    q_lower = np.percentile(data, 6.25)\n    q_upper = np.percentile(data, 93.75)\n    return data[(data < q_lower) | (data > q_upper)].tolist()\n\n\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT,\n    title_font_size=28,\n    label_font_size=18,\n    major_label_font_size=16,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\nboxen_chart = pygal.XY(\n    title=\"boxen-basic · pygal · anyplot.ai\",\n    x_title=\"Endpoint\",\n    y_title=\"Response Time (ms)\",\n    width=4800,\n    height=2700,\n    style=custom_style,\n    show_legend=True,\n    range=(0, 1200),\n    show_dots=True,\n    dots_size=6,\n)\n\nfor endpoint_idx, endpoint in enumerate(endpoints):\n    data = datasets[endpoint_idx]\n    lv = get_letter_values(data)\n\n    # Add data points for each letter value level to create nested boxes\n    # Sixteenths - outermost box\n    s_lower, s_upper = lv[\"sixteenths\"]\n    boxen_chart.add(f\"{endpoint}: Sixteenths\", [(endpoint_idx, s_lower), (endpoint_idx, s_upper)], stroke_width=2)\n\n    # Eighths - middle outer box\n    e_lower, e_upper = lv[\"eighths\"]\n    boxen_chart.add(f\"{endpoint}: Eighths\", [(endpoint_idx, e_lower), (endpoint_idx, e_upper)], stroke_width=2)\n\n    # Quartiles - middle inner box (IQR)\n    q_lower, q_upper = lv[\"quartiles\"]\n    boxen_chart.add(f\"{endpoint}: Quartiles\", [(endpoint_idx, q_lower), (endpoint_idx, q_upper)], stroke_width=4)\n\n    # Median - innermost\n    m_val = lv[\"median\"][0]\n    boxen_chart.add(f\"{endpoint}: Median\", [(endpoint_idx, m_val)], stroke_width=6)\n\n    # Outliers\n    outliers = get_outliers(data)\n    if outliers:\n        outlier_x = [endpoint_idx + np.random.normal(0, 0.06) for _ in outliers]\n        outlier_points = list(zip(outlier_x, outliers, strict=False))\n        boxen_chart.add(f\"{endpoint}: Outliers\", outlier_points, dots_size=4)\n\nboxen_chart.x_labels = endpoints\n\nboxen_chart.render_to_png(f\"plot-{THEME}.png\")\n\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(boxen_chart.render())\n"}