{"spec_id":"bar-3d-categorical","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nbar-3d-categorical: 3D Bar Chart for Categorical Comparison\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 82/100 | Created: 2026-05-15\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\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_COLOR = \"#D0CEC7\" if THEME == \"light\" else \"#2D2D2A\"\n\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data\nnp.random.seed(42)\nproducts = [\"Electronics\", \"Clothing\", \"Food\", \"Sports\"]\nregions = [\"North\", \"South\", \"East\", \"West\", \"Central\"]\nn_prod, n_reg = len(products), len(regions)\n\nbase = np.array([85, 60, 45, 55])\nsales = base[:, None] + np.random.randint(-18, 22, size=(n_prod, n_reg))\nz_max = int(sales.max()) + 10\n\nDW = 0.42\n\n# Plot\nfig = go.Figure()\n\nfor p_idx, prod in enumerate(products):\n    xs, ys, zs = [], [], []\n    ii, jj, kk = [], [], []\n\n    for r_idx in range(n_reg):\n        xi, yi, h = p_idx, r_idx, float(sales[p_idx, r_idx])\n        x0, x1 = xi - DW / 2, xi + DW / 2\n        y0, y1 = yi - DW / 2, yi + DW / 2\n        vx = [x0, x1, x1, x0, x0, x1, x1, x0]\n        vy = [y0, y0, y1, y1, y0, y0, y1, y1]\n        vz = [0, 0, 0, 0, h, h, h, h]\n        fi = [0, 0, 4, 4, 0, 0, 2, 2, 0, 0, 1, 1]\n        fj = [1, 2, 5, 6, 1, 5, 3, 7, 3, 7, 2, 6]\n        fk = [2, 3, 6, 7, 5, 4, 7, 6, 7, 4, 6, 5]\n        n = len(xs)\n        xs.extend(vx)\n        ys.extend(vy)\n        zs.extend(vz)\n        ii.extend(v + n for v in fi)\n        jj.extend(v + n for v in fj)\n        kk.extend(v + n for v in fk)\n\n    fig.add_trace(\n        go.Mesh3d(\n            x=xs,\n            y=ys,\n            z=zs,\n            i=ii,\n            j=jj,\n            k=kk,\n            color=IMPRINT[p_idx],\n            opacity=1.0,\n            name=prod,\n            showlegend=True,\n            flatshading=True,\n            lighting={\"ambient\": 0.7, \"diffuse\": 0.7, \"specular\": 0.05, \"roughness\": 0.8},\n            lightposition={\"x\": 3, \"y\": -3, \"z\": 8},\n        )\n    )\n\n# Value labels on top of each bar\nlx, ly, lz, lt = [], [], [], []\nfor p_idx in range(n_prod):\n    for r_idx in range(n_reg):\n        lx.append(p_idx)\n        ly.append(r_idx)\n        lz.append(float(sales[p_idx, r_idx]) + 2)\n        lt.append(str(int(sales[p_idx, r_idx])))\n\nfig.add_trace(\n    go.Scatter3d(\n        x=lx, y=ly, z=lz, mode=\"text\", text=lt, textfont={\"size\": 14, \"color\": INK}, showlegend=False, hoverinfo=\"skip\"\n    )\n)\n\n# Style\nfig.update_layout(\n    title={\n        \"text\": \"bar-3d-categorical · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n        \"y\": 0.98,\n        \"yanchor\": \"top\",\n    },\n    scene={\n        \"xaxis\": {\n            \"ticktext\": products,\n            \"tickvals\": list(range(n_prod)),\n            \"title\": {\"text\": \"Product Category\", \"font\": {\"size\": 22, \"color\": INK}},\n            \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n            \"gridcolor\": GRID_COLOR,\n            \"backgroundcolor\": PAGE_BG,\n            \"showbackground\": True,\n            \"linecolor\": INK_SOFT,\n            \"showgrid\": True,\n        },\n        \"yaxis\": {\n            \"ticktext\": regions,\n            \"tickvals\": list(range(n_reg)),\n            \"title\": {\"text\": \"Sales Region\", \"font\": {\"size\": 22, \"color\": INK}},\n            \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n            \"gridcolor\": GRID_COLOR,\n            \"backgroundcolor\": PAGE_BG,\n            \"showbackground\": True,\n            \"linecolor\": INK_SOFT,\n            \"showgrid\": True,\n        },\n        \"zaxis\": {\n            \"title\": {\"text\": \"Sales ($K)\", \"font\": {\"size\": 22, \"color\": INK}},\n            \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n            \"gridcolor\": GRID_COLOR,\n            \"backgroundcolor\": PAGE_BG,\n            \"showbackground\": True,\n            \"linecolor\": INK_SOFT,\n            \"showgrid\": True,\n            \"range\": [0, z_max],\n        },\n        \"camera\": {\"eye\": {\"x\": 1.5, \"y\": -2.2, \"z\": 1.2}, \"up\": {\"x\": 0, \"y\": 0, \"z\": 1}},\n    },\n    paper_bgcolor=PAGE_BG,\n    legend={\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"font\": {\"color\": INK_SOFT, \"size\": 16},\n        \"title\": {\"text\": \"Product\", \"font\": {\"color\": INK, \"size\": 17}},\n        \"x\": 0.02,\n        \"y\": 0.95,\n    },\n    margin={\"l\": 0, \"r\": 20, \"t\": 60, \"b\": 0},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}