{"spec_id":"dashboard-metrics-tiles","library":"altair","language":"python","code":"\"\"\" anyplot.ai\ndashboard-metrics-tiles: Real-Time Dashboard Tiles\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\n\nimport altair as alt\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\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\"\n\n# Okabe-Ito colours mapped to status roles\nGOOD_COLOR = \"#009E73\"\nWARN_COLOR = \"#DDCC77\"  # imprint amber — semantic warning\nCRIT_COLOR = \"#AE3030\"  # imprint red — semantic critical\nSTATUS_COLORS = {\"good\": GOOD_COLOR, \"warning\": WARN_COLOR, \"critical\": CRIT_COLOR}\n\n# Data - KPI metrics with sparkline history\nnp.random.seed(42)\n\nmetrics = [\n    {\"name\": \"CPU Usage\", \"value\": 45, \"unit\": \"%\", \"change\": -5.2, \"status\": \"good\"},\n    {\"name\": \"Memory\", \"value\": 72, \"unit\": \"%\", \"change\": 8.1, \"status\": \"warning\"},\n    {\"name\": \"Response Time\", \"value\": 120, \"unit\": \"ms\", \"change\": -15.3, \"status\": \"good\"},\n    {\"name\": \"Requests/sec\", \"value\": 2847, \"unit\": \"\", \"change\": 12.4, \"status\": \"good\"},\n    {\"name\": \"Error Rate\", \"value\": 0.8, \"unit\": \"%\", \"change\": 0.3, \"status\": \"warning\"},\n    {\"name\": \"Disk I/O\", \"value\": 156, \"unit\": \"MB/s\", \"change\": -2.1, \"status\": \"good\"},\n]\n\n# Build tiles inline (no helper function)\ntiles = []\nfor idx, m in enumerate(metrics):\n    # Sparkline history\n    np.random.seed(100 + idx * 17)\n    n = 20\n    noise = np.cumsum(np.random.randn(n) * 5)\n    trend_dir = -1 if m[\"change\"] < 0 else 1\n    trend = np.linspace(trend_dir * 15, 0, n)\n    values = 50 + noise + trend\n    v_min, v_max = values.min(), values.max()\n    values = 20 + 60 * (values - v_min) / (v_max - v_min + 0.001)\n    spark_df = pd.DataFrame({\"t\": range(n), \"v\": values})\n\n    # Format headline value\n    if m[\"value\"] >= 1000:\n        val_str = f\"{m['value']:,.0f}\"\n    elif m[\"value\"] < 1:\n        val_str = f\"{m['value']:.1f}\"\n    else:\n        val_str = f\"{m['value']:.0f}\"\n    display_val = f\"{val_str}{m['unit']}\"\n\n    # Change indicator\n    arrow = \"▲\" if m[\"change\"] > 0 else \"▼\"\n    change_text = f\"{arrow} {abs(m['change']):.1f}%\"\n    favorable = m[\"change\"] < 0 if m[\"name\"] != \"Requests/sec\" else m[\"change\"] > 0\n    change_color = GOOD_COLOR if favorable else CRIT_COLOR\n    tile_color = STATUS_COLORS[m[\"status\"]]\n\n    # Sparkline area chart\n    sparkline = (\n        alt.Chart(spark_df)\n        .mark_area(\n            line={\"color\": tile_color, \"strokeWidth\": 2},\n            color=alt.Gradient(\n                gradient=\"linear\",\n                stops=[\n                    alt.GradientStop(color=f\"{tile_color}55\", offset=0),\n                    alt.GradientStop(color=f\"{tile_color}0a\", offset=1),\n                ],\n                x1=1,\n                x2=1,\n                y1=1,\n                y2=0,\n            ),\n        )\n        .encode(x=alt.X(\"t:Q\", axis=None), y=alt.Y(\"v:Q\", axis=None, scale=alt.Scale(domain=[0, 100])))\n        .properties(width=190, height=55)\n    )\n\n    # Change indicator text row\n    cdf = pd.DataFrame([{\"x\": 0.5, \"label\": change_text}])\n    change_row = (\n        alt.Chart(cdf)\n        .mark_text(fontSize=16, fontWeight=\"bold\", color=change_color)\n        .encode(x=alt.X(\"x:Q\", axis=None, scale=alt.Scale(domain=[0, 1])), text=\"label:N\")\n        .properties(width=190, height=22)\n    )\n\n    tile = alt.vconcat(sparkline, change_row, spacing=4).properties(\n        title=alt.Title(\n            text=[display_val, m[\"name\"]],\n            fontSize=36,\n            subtitleFontSize=16,\n            subtitleColor=INK_SOFT,\n            color=INK,\n            anchor=\"middle\",\n            offset=6,\n        )\n    )\n    tiles.append(tile)\n\n# Arrange in 3×2 grid\nrow1 = alt.hconcat(tiles[0], tiles[1], tiles[2], spacing=18)\nrow2 = alt.hconcat(tiles[3], tiles[4], tiles[5], spacing=18)\n\nchart = (\n    alt.vconcat(row1, row2, spacing=18)\n    .properties(\n        background=PAGE_BG,\n        title=alt.Title(\n            text=\"dashboard-metrics-tiles · python · altair · anyplot.ai\",\n            fontSize=16,\n            color=INK,\n            anchor=\"middle\",\n            offset=12,\n        ),\n    )\n    .configure_view(stroke=INK_SOFT, strokeWidth=1, cornerRadius=8, fill=ELEVATED_BG)\n    .configure_concat(spacing=18)\n)\n\n# Save PNG then pad to exact 3200×1800\nchart.save(f\"plot-{THEME}.png\", scale_factor=4.0)\n\nTW, TH = 3200, 1800\n_img = Image.open(f\"plot-{THEME}.png\").convert(\"RGB\")\n_w, _h = _img.size\nif _w > TW or _h > TH:\n    raise SystemExit(\n        f\"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. \"\n        f\"Shrink chart .properties(width=, height=) values and re-render.\"\n    )\nif _w < TW or _h < TH:\n    _canvas = Image.new(\"RGB\", (TW, TH), PAGE_BG)\n    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))\n    _canvas.save(f\"plot-{THEME}.png\")\n\nchart.save(f\"plot-{THEME}.html\")\n"}