{"spec_id":"dashboard-metrics-tiles","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\ndashboard-metrics-tiles: Real-Time Dashboard Tiles\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-21\n\"\"\"\n\nimport os\nimport sys\nimport time\nfrom pathlib import Path\n\n\n# bokeh.py shadows the installed bokeh package when Python adds this file's\n# directory to sys.path[0]; remove it so imports resolve to the package.\n_here = os.path.dirname(os.path.abspath(__file__))\nsys.path[:] = [p for p in sys.path if os.path.abspath(p or \".\") != _here]\ndel _here\n\nimport numpy as np\nfrom bokeh.io import output_file, save\nfrom bokeh.layouts import column, gridplot\nfrom bokeh.models import ColumnDataSource, Label\nfrom bokeh.plotting import figure\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\n\n# Theme tokens\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 semantic colors for status and change indicators\nSTATUS_COLORS = {\"good\": \"#009E73\", \"warning\": \"#DDCC77\", \"critical\": \"#AE3030\"}  # imprint semantic anchors\nSPARKLINE_COLOR = \"#4467A3\"  # Okabe-Ito position 3\nFAVORABLE_COLOR = \"#009E73\"  # Okabe-Ito position 1\nUNFAVORABLE_COLOR = \"#AE3030\"  # imprint red — unfavorable\n\n# Metrics where a positive change is unfavorable\nUNFAVORABLE_WHEN_UP = {\"Error Rate\", \"Response Time\"}\n\n# Data - 6 ops monitoring metric tiles\nnp.random.seed(42)\n\nmetrics = [\n    {\n        \"name\": \"CPU Usage\",\n        \"value\": 45,\n        \"unit\": \"%\",\n        \"history\": np.clip(40 + np.cumsum(np.random.randn(30) * 2), 20, 80),\n        \"change\": -5.2,\n        \"status\": \"good\",\n    },\n    {\n        \"name\": \"Memory\",\n        \"value\": 72,\n        \"unit\": \"%\",\n        \"history\": np.clip(65 + np.cumsum(np.random.randn(30) * 1.5), 50, 90),\n        \"change\": 8.1,\n        \"status\": \"warning\",\n    },\n    {\n        \"name\": \"Response Time\",\n        \"value\": 120,\n        \"unit\": \"ms\",\n        \"history\": np.clip(100 + np.cumsum(np.random.randn(30) * 10), 50, 200),\n        \"change\": -15.3,\n        \"status\": \"good\",\n    },\n    {\n        \"name\": \"Error Rate\",\n        \"value\": 2.4,\n        \"unit\": \"%\",\n        \"history\": np.clip(2 + np.cumsum(np.random.randn(30) * 0.3), 0.5, 5),\n        \"change\": 12.5,\n        \"status\": \"critical\",\n    },\n    {\n        \"name\": \"Throughput\",\n        \"value\": 1250,\n        \"unit\": \"req/s\",\n        \"history\": np.clip(1200 + np.cumsum(np.random.randn(30) * 50), 900, 1500),\n        \"change\": 3.7,\n        \"status\": \"good\",\n    },\n    {\n        \"name\": \"Active Users\",\n        \"value\": 8432,\n        \"unit\": \"\",\n        \"history\": np.clip(8000 + np.cumsum(np.random.randn(30) * 200), 7000, 10000),\n        \"change\": -2.1,\n        \"status\": \"warning\",\n    },\n]\n\n# Canvas: 3200x1800 total\n# title_fig=160h, gridplot=2x820h rows × 3x1066w cols → 1640h + 160h = 1800h; 3198w ≈ 3200w\nTILE_WIDTH = 1066\nTILE_HEIGHT = 820\n\ntiles = []\n\nfor metric in metrics:\n    is_positive_change = metric[\"change\"] > 0\n    is_favorable = not is_positive_change if metric[\"name\"] in UNFAVORABLE_WHEN_UP else is_positive_change\n    change_color = FAVORABLE_COLOR if is_favorable else UNFAVORABLE_COLOR\n    arrow = \"▲\" if is_positive_change else \"▼\"\n    status_color = STATUS_COLORS[metric[\"status\"]]\n\n    p = figure(\n        width=TILE_WIDTH, height=TILE_HEIGHT, toolbar_location=None, tools=\"\", x_range=(0, 1), y_range=(-0.02, 1.12)\n    )\n\n    # Hide axes and grid; apply tile chrome\n    p.xaxis.visible = False\n    p.yaxis.visible = False\n    p.xgrid.visible = False\n    p.ygrid.visible = False\n    p.outline_line_color = INK_SOFT\n    p.background_fill_color = ELEVATED_BG\n    p.border_fill_color = PAGE_BG\n\n    # Status bar across top of tile\n    p.quad(left=0, right=1, top=1.08, bottom=1.0, fill_color=status_color, line_color=None)\n\n    # Metric name\n    p.add_layout(\n        Label(\n            x=0.5,\n            y=0.85,\n            text=metric[\"name\"],\n            text_font_size=\"20pt\",\n            text_font_style=\"bold\",\n            text_color=INK,\n            text_align=\"center\",\n            text_baseline=\"middle\",\n        )\n    )\n\n    # Prominent current value\n    value_text = f\"{metric['value']}{metric['unit']}\"\n    p.add_layout(\n        Label(\n            x=0.5,\n            y=0.63,\n            text=value_text,\n            text_font_size=\"42pt\",\n            text_font_style=\"bold\",\n            text_color=INK,\n            text_align=\"center\",\n            text_baseline=\"middle\",\n        )\n    )\n\n    # Change indicator with directional arrow\n    change_text = f\"{arrow} {abs(metric['change']):.1f}%\"\n    p.add_layout(\n        Label(\n            x=0.5,\n            y=0.43,\n            text=change_text,\n            text_font_size=\"22pt\",\n            text_font_style=\"bold\",\n            text_color=change_color,\n            text_align=\"center\",\n            text_baseline=\"middle\",\n        )\n    )\n\n    # Sparkline — normalize history to [0.05, 0.33]\n    history = np.array(metric[\"history\"])\n    hist_min, hist_max = history.min(), history.max()\n    hist_range = hist_max - hist_min if hist_max != hist_min else 1.0\n    y_norm = 0.05 + (history - hist_min) / hist_range * 0.28\n    x_norm = np.linspace(0.08, 0.92, len(history))\n\n    # Filled area under sparkline\n    y_fill = np.concatenate([y_norm, [0.05, 0.05]])\n    x_fill = np.concatenate([x_norm, [x_norm[-1], x_norm[0]]])\n    p.patch(x_fill, y_fill, fill_color=SPARKLINE_COLOR, fill_alpha=0.25, line_color=None)\n\n    # Sparkline line (thicker for visibility)\n    source = ColumnDataSource(data={\"x\": x_norm, \"y\": y_norm})\n    p.line(\"x\", \"y\", source=source, line_width=5, line_color=SPARKLINE_COLOR)\n\n    # Endpoint dot marking the current value\n    p.scatter(\n        x=[x_norm[-1]], y=[y_norm[-1]], size=14, fill_color=SPARKLINE_COLOR, line_color=ELEVATED_BG, line_width=2.5\n    )\n\n    tiles.append(p)\n\n# 3x2 grid of tiles — toolbar_location=None is critical: gridplot default toolbar\n# adds ~139px above the canvas, shrinking the screenshot height below 1800\ngrid = gridplot(\n    [[tiles[0], tiles[1], tiles[2]], [tiles[3], tiles[4], tiles[5]]], merge_tools=False, toolbar_location=None\n)\n\n# Title figure (full canvas width, 160px tall)\ntitle_fig = figure(width=3200, height=160, toolbar_location=None, tools=\"\", x_range=(0, 1), y_range=(0, 1))\ntitle_fig.xaxis.visible = False\ntitle_fig.yaxis.visible = False\ntitle_fig.xgrid.visible = False\ntitle_fig.ygrid.visible = False\ntitle_fig.outline_line_color = None\ntitle_fig.background_fill_color = PAGE_BG\ntitle_fig.border_fill_color = PAGE_BG\n\ntitle_fig.add_layout(\n    Label(\n        x=0.5,\n        y=0.5,\n        text=\"dashboard-metrics-tiles · python · bokeh · anyplot.ai\",\n        text_font_size=\"28pt\",\n        text_font_style=\"bold\",\n        text_color=INK,\n        text_align=\"center\",\n        text_baseline=\"middle\",\n    )\n)\n\nfinal_layout = column(title_fig, grid)\n\n# Save interactive HTML\noutput_file(f\"plot-{THEME}.html\")\nsave(final_layout)\n\n# Screenshot to PNG via headless Chrome (Selenium 4 / Selenium Manager)\nW, H = 3200, 1800\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{H}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\ndriver = webdriver.Chrome(options=opts)\n# --window-size includes browser chrome; use CDP to set exact viewport\ndriver.execute_cdp_cmd(\n    \"Emulation.setDeviceMetricsOverride\", {\"width\": W, \"height\": H, \"deviceScaleFactor\": 1, \"mobile\": False}\n)\ndriver.get(f\"file://{Path(f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\ndriver.execute_script(\n    f\"document.body.style.margin='0'; document.body.style.padding='0';document.body.style.backgroundColor='{PAGE_BG}';\"\n)\ndriver.save_screenshot(f\"plot-{THEME}.png\")\ndriver.quit()\n"}