{"spec_id":"confusion-matrix","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nconfusion-matrix: Confusion Matrix Heatmap\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom sklearn.datasets import load_iris\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import train_test_split\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 - Iris classification\niris = load_iris()\nX, y = iris.data, iris.target\nclass_names = iris.target_names\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n\n# Train classifier\nclf = RandomForestClassifier(random_state=42)\nclf.fit(X_train, y_train)\ny_pred = clf.predict(X_test)\n\n# Build confusion matrix\nn_classes = len(class_names)\nconfusion_matrix = np.zeros((n_classes, n_classes))\nfor true_label, pred_label in zip(y_test, y_pred, strict=True):\n    confusion_matrix[true_label, pred_label] += 1\n\n# Plot\nfig, ax = plt.subplots(figsize=(12, 12), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Create heatmap using Blues colormap\nim = ax.imshow(confusion_matrix, cmap=\"Blues\", aspect=\"equal\")\n\n# Add colorbar with theme-adaptive styling\ncbar = ax.figure.colorbar(im, ax=ax, fraction=0.046, pad=0.04)\ncbar.ax.tick_params(labelsize=16, colors=INK_SOFT)\ncbar.ax.yaxis.set_tick_params(color=INK_SOFT)\ncbar.set_label(\"Count\", fontsize=18, color=INK)\nfor spine in cbar.ax.spines.values():\n    spine.set_edgecolor(INK_SOFT)\n\n# Set ticks and labels\nax.set_xticks(np.arange(n_classes))\nax.set_yticks(np.arange(n_classes))\nax.set_xticklabels(class_names, fontsize=18, color=INK_SOFT)\nax.set_yticklabels(class_names, fontsize=18, color=INK_SOFT)\n\n# Rotate x-axis labels for readability\nplt.setp(ax.get_xticklabels(), rotation=45, ha=\"right\", rotation_mode=\"anchor\")\n\n# Annotate cells with counts and percentages\nfor i in range(n_classes):\n    for j in range(n_classes):\n        count = confusion_matrix[i, j]\n        row_total = confusion_matrix[i, :].sum()\n        if row_total > 0:\n            percentage = count / row_total * 100\n        else:\n            percentage = 0\n\n        # Choose text color based on background intensity\n        text_color = \"#FFFDF6\" if count > confusion_matrix.max() * 0.5 else \"#1A1A17\"\n\n        # Display count and percentage\n        text = ax.text(\n            j,\n            i,\n            f\"{int(count)}\\n({percentage:.1f}%)\",\n            ha=\"center\",\n            va=\"center\",\n            color=text_color,\n            fontsize=16,\n            fontweight=\"bold\",\n        )\n\n# Grid lines between cells\nax.set_xticks(np.arange(n_classes + 1) - 0.5, minor=True)\nax.set_yticks(np.arange(n_classes + 1) - 0.5, minor=True)\nax.grid(which=\"minor\", color=INK_SOFT, linestyle=\"-\", linewidth=0.8, alpha=0.3)\nax.tick_params(which=\"minor\", bottom=False, left=False)\n\n# Spine styling\nfor spine in (\"top\", \"right\"):\n    ax.spines[spine].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax.spines[spine].set_color(INK_SOFT)\n\n# Labels and title\nax.set_xlabel(\"Predicted Label\", fontsize=20, color=INK)\nax.set_ylabel(\"True Label\", fontsize=20, color=INK)\nax.set_title(\n    \"Iris Classification · confusion-matrix · matplotlib · anyplot.ai\",\n    fontsize=24,\n    fontweight=\"medium\",\n    color=INK,\n    pad=20,\n)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}