{"spec_id":"gauge-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\ngauge-basic: Basic Gauge Chart\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-06-30\n\"\"\"\n\nimport os\nimport sys\n\n\n# Script named matplotlib.py shadows the installed package when run from its own directory.\n# Removing the first sys.path entry (the script's directory) before any matplotlib import\n# restores the normal package lookup — the venv site-packages takes over.\nsys.path.pop(0)\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\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# Imprint semantic anchors (red / amber / green traffic-light)\nZONE_BAD = \"#AE3030\"  # matte red — semantic bad\nZONE_WARN = \"#DDCC77\"  # amber — semantic warning\nZONE_GOOD = \"#009E73\"  # brand green — semantic good\n\n# Data\nvalue = 72\nmin_value = 0\nmax_value = 100\nthresholds = [30, 70]\n\n# Gauge geometry: 180° arc (left=0, right=100)\nangle_range = 180\nvalue_normalized = (value - min_value) / (max_value - min_value)\nneedle_angle = 180 - value_normalized * angle_range\n\n# Plot — square canvas (2400×2400) for optimal gauge proportions\nfig, ax = plt.subplots(figsize=(6, 6), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Color zones with labels\nzone_colors = [ZONE_BAD, ZONE_WARN, ZONE_GOOD]\nzone_boundaries = [min_value] + thresholds + [max_value]\nzone_labels = [\"Poor\", \"Fair\", \"Good\"]\n\nfor i in range(len(zone_colors)):\n    start_norm = (zone_boundaries[i] - min_value) / (max_value - min_value)\n    end_norm = (zone_boundaries[i + 1] - min_value) / (max_value - min_value)\n    theta1 = 180 - end_norm * angle_range\n    theta2 = 180 - start_norm * angle_range\n    wedge = mpatches.Wedge(\n        center=(0, 0),\n        r=1.0,\n        theta1=theta1,\n        theta2=theta2,\n        width=0.3,\n        facecolor=zone_colors[i],\n        edgecolor=PAGE_BG,\n        linewidth=2,\n    )\n    ax.add_patch(wedge)\n\n    # Zone label at arc midpoint (tangential orientation)\n    mid_norm = (start_norm + end_norm) / 2\n    mid_angle = 180 - mid_norm * angle_range\n    mid_rad = np.radians(mid_angle)\n    ax.text(\n        0.85 * np.cos(mid_rad),\n        0.85 * np.sin(mid_rad),\n        zone_labels[i],\n        ha=\"center\",\n        va=\"center\",\n        fontsize=8,\n        fontweight=\"bold\",\n        color=PAGE_BG,\n        rotation=mid_angle - 90,\n    )\n\n# Inner fill (matches page background, cleans dial center)\nax.add_patch(mpatches.Wedge(center=(0, 0), r=0.65, theta1=0, theta2=180, facecolor=PAGE_BG, edgecolor=\"none\"))\n\n# Tick marks: minor and major\nmajor_ticks = [0, 25, 50, 75, 100]\nminor_ticks = [t for t in range(0, 101, 5) if t not in major_ticks]\n\nfor tick in minor_ticks:\n    tick_norm = (tick - min_value) / (max_value - min_value)\n    tick_angle = 180 - tick_norm * angle_range\n    tick_rad = np.radians(tick_angle)\n    ax.plot(\n        [1.02 * np.cos(tick_rad), 1.05 * np.cos(tick_rad)],\n        [1.02 * np.sin(tick_rad), 1.05 * np.sin(tick_rad)],\n        color=INK_SOFT,\n        linewidth=1.5,\n    )\n\nfor tick in major_ticks:\n    tick_norm = (tick - min_value) / (max_value - min_value)\n    tick_angle = 180 - tick_norm * angle_range\n    tick_rad = np.radians(tick_angle)\n    ax.plot(\n        [1.02 * np.cos(tick_rad), 1.09 * np.cos(tick_rad)],\n        [1.02 * np.sin(tick_rad), 1.09 * np.sin(tick_rad)],\n        color=INK,\n        linewidth=3,\n    )\n    ax.text(\n        1.19 * np.cos(tick_rad),\n        1.19 * np.sin(tick_rad),\n        str(tick),\n        ha=\"center\",\n        va=\"center\",\n        fontsize=16,\n        fontweight=\"bold\",\n        color=INK_SOFT,\n    )\n\n# Needle\nneedle_rad = np.radians(needle_angle)\nax.plot(\n    [0, 0.78 * np.cos(needle_rad)],\n    [0, 0.78 * np.sin(needle_rad)],\n    color=INK,\n    linewidth=5,\n    solid_capstyle=\"round\",\n    zorder=9,\n)\n\n# Center cap (two-tone for definition)\nax.add_patch(plt.Circle((0, 0), 0.09, facecolor=INK, edgecolor=\"none\", zorder=10))\nax.add_patch(plt.Circle((0, 0), 0.035, facecolor=PAGE_BG, edgecolor=\"none\", zorder=11))\n\n# Value label and context\nax.text(0, -0.22, f\"{value}\", ha=\"center\", va=\"center\", fontsize=56, fontweight=\"bold\", color=ZONE_GOOD)\nax.text(0, -0.46, \"Current Sales\", ha=\"center\", va=\"center\", fontsize=18, color=INK_MUTED)\n\n# Title\ntitle = \"gauge-basic · python · matplotlib · anyplot.ai\"\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK, pad=20)\n\n# Frame — square axes to match square canvas\nax.set_aspect(\"equal\")\nax.set_xlim(-1.5, 1.5)\nax.set_ylim(-1.15, 1.85)\nax.axis(\"off\")\n\nfig.subplots_adjust(left=0.03, right=0.97, top=0.88, bottom=0.05)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}