{"spec_id":"errorbar-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nerrorbar-basic: Basic Error Bar Plot\nLibrary: plotly 6.8.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-06-30\n\"\"\"\n\nimport importlib\nimport os\nimport sys\n\n\n# Drop script directory from sys.path so the `plotly` package resolves, not this file\nsys.path[:] = [p for p in sys.path if os.path.abspath(p or \".\") != os.path.dirname(os.path.abspath(__file__))]\ngo = importlib.import_module(\"plotly.graph_objects\")\nnp = importlib.import_module(\"numpy\")\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\nCTRL_FILL = \"rgba(26,26,23,0.05)\" if THEME == \"light\" else \"rgba(240,239,232,0.05)\"\n\n# Imprint palette — one hue per group (positions 1–6)\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#2ABCCD\", \"#954477\"]\n\n# Data — clinical trial response (mg/dL) with asymmetric 95% confidence intervals\ngroups = [\"Control\", \"Treatment A\", \"Treatment B\", \"Treatment C\", \"Treatment D\", \"Treatment E\"]\nx_positions = list(range(len(groups)))\nmeans = np.array([42.3, 51.7, 63.2, 47.8, 72.4, 58.9])\nerr_upper = np.array([5.4, 7.8, 4.1, 9.3, 3.6, 6.5])\nerr_lower = np.array([4.1, 6.2, 3.8, 7.9, 4.7, 5.1])\n\n# Control CI bounds — reference band for comparison\ncontrol_lo = float(means[0] - err_lower[0])\ncontrol_hi = float(means[0] + err_upper[0])\n\nfig = go.Figure()\n\n# Subtle control CI reference band (drawn below data)\nfig.add_hrect(y0=control_lo, y1=control_hi, fillcolor=CTRL_FILL, line_width=0, layer=\"below\")\n\n# Control baseline dashed reference line\nfig.add_hline(y=float(means[0]), line_dash=\"dot\", line_color=INK_MUTED, line_width=1.5)\n\n# Per-group traces — Imprint palette assigns each group a distinct hue\nfor i, (group, x, mean, eu, el) in enumerate(\n    zip(groups, x_positions, means.tolist(), err_upper.tolist(), err_lower.tolist(), strict=False)\n):\n    color = IMPRINT_PALETTE[i]\n    fig.add_trace(\n        go.Scatter(\n            x=[x],\n            y=[mean],\n            mode=\"markers\",\n            marker={\"size\": 20, \"color\": color, \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n            error_y={\n                \"type\": \"data\",\n                \"symmetric\": False,\n                \"array\": [eu],\n                \"arrayminus\": [el],\n                \"visible\": True,\n                \"thickness\": 3,\n                \"width\": 12,\n                \"color\": color,\n            },\n            name=group,\n            customdata=[[group, round(mean - el, 1), round(mean + eu, 1)]],\n            hovertemplate=(\n                \"<b>%{customdata[0]}</b><br>\"\n                \"Mean: %{y:.1f} mg/dL<br>\"\n                \"95%% CI: [%{customdata[1]}, %{customdata[2]}]\"\n                \"<extra></extra>\"\n            ),\n        )\n    )\n\n# Annotation: Treatment D (index 4) — highest mean response\nfig.add_annotation(\n    x=4,\n    y=float(means[4] + err_upper[4]),\n    text=\"Peak response\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=INK_SOFT,\n    arrowwidth=1.5,\n    ax=0,\n    ay=-32,\n    font={\"size\": 10, \"color\": INK_SOFT},\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=3,\n    xanchor=\"center\",\n)\n\n# Annotation: control baseline label\nfig.add_annotation(\n    x=5.55,\n    y=float(means[0]),\n    text=\"Control<br>baseline\",\n    showarrow=False,\n    font={\"size\": 10, \"color\": INK_MUTED},\n    xanchor=\"left\",\n    yanchor=\"middle\",\n    bgcolor=ELEVATED_BG,\n    borderpad=2,\n)\n\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"Clinical Response by Group · errorbar-basic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Experimental Group\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"tickmode\": \"array\",\n        \"tickvals\": x_positions,\n        \"ticktext\": groups,\n        \"showgrid\": False,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n        \"ticks\": \"\",\n        \"range\": [-0.6, 6.0],\n    },\n    yaxis={\n        \"title\": {\"text\": \"Response (mg/dL)\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zeroline\": False,\n        \"range\": [28, 88],\n        \"ticks\": \"\",\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"l\": 80, \"r\": 80, \"t\": 80, \"b\": 60},\n    showlegend=True,\n    legend={\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"x\": 0.98,\n        \"y\": 0.98,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"top\",\n    },\n    hoverlabel={\"bgcolor\": ELEVATED_BG, \"bordercolor\": INK_SOFT, \"font\": {\"color\": INK, \"size\": 10}},\n)\n\n# Save — landscape 3200 × 1800 (width=800 × scale=4, height=450 × scale=4)\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}