{"spec_id":"bar-3d-categorical","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nbar-3d-categorical: 3D Bar Chart for Categorical Comparison\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 80/100 | Created: 2026-05-15\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom mpl_toolkits.mplot3d import Axes3D\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Data: retail sales (thousands USD) by product category and region\nproducts = [\"Electronics\", \"Clothing\", \"Home & Garden\", \"Sports\"]\nregions = [\"North\", \"South\", \"East\", \"West\"]\n\nsales = np.array([[142, 98, 115, 87], [76, 103, 91, 118], [55, 71, 63, 49], [88, 95, 72, 110]])\n\n# Plot\nfig = plt.figure(figsize=(16, 9), facecolor=PAGE_BG)\nax = fig.add_subplot(111, projection=\"3d\", computed_zorder=False)\nfig.subplots_adjust(left=0.0, right=0.85, bottom=0.05, top=0.92)\n\n# Theme-adaptive pane styling\nfor pane in (ax.xaxis.pane, ax.yaxis.pane, ax.zaxis.pane):\n    pane.fill = False\n    pane.set_edgecolor(INK_SOFT)\n    pane.set_alpha(0.4)\n\nax.grid(True, alpha=0.10, linewidth=0.6, color=INK)\n\nnorm = plt.Normalize(vmin=sales.min(), vmax=sales.max())\ncmap = plt.get_cmap(\"viridis\")\n\nbar_width = 0.55\nbar_depth = 0.55\nnum_products = len(products)\nnum_regions = len(regions)\n\nfor i in range(num_products):\n    for j in range(num_regions):\n        value = sales[i, j]\n        color = cmap(norm(value))\n        ax.bar3d(\n            i - bar_width / 2, j - bar_depth / 2, 0, bar_width, bar_depth, value, color=color, alpha=0.88, shade=True\n        )\n        ax.text(i, j, value + 5, f\"{value}\", ha=\"center\", va=\"bottom\", fontsize=10, color=INK, fontweight=\"semibold\")\n\n# View angle and z-axis headroom for value labels\nax.view_init(elev=28, azim=-48)\nax.set_zlim(0, 165)\n\n# Axis ticks and labels\nax.set_xticks(range(num_products))\nax.set_xticklabels(products, fontsize=13, color=INK_SOFT)\nax.set_yticks(range(num_regions))\nax.set_yticklabels(regions, fontsize=13, color=INK_SOFT)\nax.tick_params(axis=\"z\", labelsize=13, colors=INK_SOFT)\n\nax.set_xlabel(\"Product Category\", fontsize=15, color=INK, labelpad=16)\nax.set_ylabel(\"Region\", fontsize=15, color=INK, labelpad=16)\nax.set_zlabel(\"$ thousands\", fontsize=14, color=INK_SOFT, labelpad=12)\n\nax.set_title(\n    \"Retail Sales by Product & Region  ·  bar-3d-categorical · matplotlib · anyplot.ai\",\n    fontsize=20,\n    fontweight=\"medium\",\n    color=INK,\n    pad=16,\n)\n\n# Colorbar — placed in its own axes to avoid tight_layout conflicts\ncbar_ax = fig.add_axes([0.87, 0.15, 0.025, 0.65])\nsm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)\nsm.set_array([])\ncbar = fig.colorbar(sm, cax=cbar_ax)\ncbar.set_label(\"Sales ($ thousands)\", fontsize=14, color=INK)\ncbar.ax.tick_params(labelsize=12, colors=INK_SOFT)\nplt.setp(cbar.ax.yaxis.get_ticklabels(), color=INK_SOFT)\ncbar.outline.set_edgecolor(INK_SOFT)\ncbar_ax.set_facecolor(PAGE_BG)\n\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}