Real-Time Dashboard Tiles — Altair

A dashboard layout displaying multiple metric tiles in a responsive grid, where each tile shows a KPI value with its label, an embedded sparkline showing recent trend, and a change indicator (up/down arrow with percentage). This visualization is essential for operations monitoring and business dashboards where multiple metrics need to be tracked simultaneously at a glance. The combination of current value, trend visualization, and change direction provides comprehensive metric context in a compact format.

Real-Time Dashboard Tiles rendered with Altair

Python source (Altair)

""" anyplot.ai
dashboard-metrics-tiles: Real-Time Dashboard Tiles
Library: altair 6.1.0 | Python 3.13.13
Quality: 91/100 | Updated: 2026-05-21
"""

import os

import altair as alt
import numpy as np
import pandas as pd
from PIL import Image


THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"

# Okabe-Ito colours mapped to status roles
GOOD_COLOR = "#009E73"
WARN_COLOR = "#DDCC77"  # imprint amber — semantic warning
CRIT_COLOR = "#AE3030"  # imprint red — semantic critical
STATUS_COLORS = {"good": GOOD_COLOR, "warning": WARN_COLOR, "critical": CRIT_COLOR}

# Data - KPI metrics with sparkline history
np.random.seed(42)

metrics = [
    {"name": "CPU Usage", "value": 45, "unit": "%", "change": -5.2, "status": "good"},
    {"name": "Memory", "value": 72, "unit": "%", "change": 8.1, "status": "warning"},
    {"name": "Response Time", "value": 120, "unit": "ms", "change": -15.3, "status": "good"},
    {"name": "Requests/sec", "value": 2847, "unit": "", "change": 12.4, "status": "good"},
    {"name": "Error Rate", "value": 0.8, "unit": "%", "change": 0.3, "status": "warning"},
    {"name": "Disk I/O", "value": 156, "unit": "MB/s", "change": -2.1, "status": "good"},
]

# Build tiles inline (no helper function)
tiles = []
for idx, m in enumerate(metrics):
    # Sparkline history
    np.random.seed(100 + idx * 17)
    n = 20
    noise = np.cumsum(np.random.randn(n) * 5)
    trend_dir = -1 if m["change"] < 0 else 1
    trend = np.linspace(trend_dir * 15, 0, n)
    values = 50 + noise + trend
    v_min, v_max = values.min(), values.max()
    values = 20 + 60 * (values - v_min) / (v_max - v_min + 0.001)
    spark_df = pd.DataFrame({"t": range(n), "v": values})

    # Format headline value
    if m["value"] >= 1000:
        val_str = f"{m['value']:,.0f}"
    elif m["value"] < 1:
        val_str = f"{m['value']:.1f}"
    else:
        val_str = f"{m['value']:.0f}"
    display_val = f"{val_str}{m['unit']}"

    # Change indicator
    arrow = "▲" if m["change"] > 0 else "▼"
    change_text = f"{arrow} {abs(m['change']):.1f}%"
    favorable = m["change"] < 0 if m["name"] != "Requests/sec" else m["change"] > 0
    change_color = GOOD_COLOR if favorable else CRIT_COLOR
    tile_color = STATUS_COLORS[m["status"]]

    # Sparkline area chart
    sparkline = (
        alt.Chart(spark_df)
        .mark_area(
            line={"color": tile_color, "strokeWidth": 2},
            color=alt.Gradient(
                gradient="linear",
                stops=[
                    alt.GradientStop(color=f"{tile_color}55", offset=0),
                    alt.GradientStop(color=f"{tile_color}0a", offset=1),
                ],
                x1=1,
                x2=1,
                y1=1,
                y2=0,
            ),
        )
        .encode(x=alt.X("t:Q", axis=None), y=alt.Y("v:Q", axis=None, scale=alt.Scale(domain=[0, 100])))
        .properties(width=190, height=55)
    )

    # Change indicator text row
    cdf = pd.DataFrame([{"x": 0.5, "label": change_text}])
    change_row = (
        alt.Chart(cdf)
        .mark_text(fontSize=16, fontWeight="bold", color=change_color)
        .encode(x=alt.X("x:Q", axis=None, scale=alt.Scale(domain=[0, 1])), text="label:N")
        .properties(width=190, height=22)
    )

    tile = alt.vconcat(sparkline, change_row, spacing=4).properties(
        title=alt.Title(
            text=[display_val, m["name"]],
            fontSize=36,
            subtitleFontSize=16,
            subtitleColor=INK_SOFT,
            color=INK,
            anchor="middle",
            offset=6,
        )
    )
    tiles.append(tile)

# Arrange in 3×2 grid
row1 = alt.hconcat(tiles[0], tiles[1], tiles[2], spacing=18)
row2 = alt.hconcat(tiles[3], tiles[4], tiles[5], spacing=18)

chart = (
    alt.vconcat(row1, row2, spacing=18)
    .properties(
        background=PAGE_BG,
        title=alt.Title(
            text="dashboard-metrics-tiles · python · altair · anyplot.ai",
            fontSize=16,
            color=INK,
            anchor="middle",
            offset=12,
        ),
    )
    .configure_view(stroke=INK_SOFT, strokeWidth=1, cornerRadius=8, fill=ELEVATED_BG)
    .configure_concat(spacing=18)
)

# Save PNG then pad to exact 3200×1800
chart.save(f"plot-{THEME}.png", scale_factor=4.0)

TW, TH = 3200, 1800
_img = Image.open(f"plot-{THEME}.png").convert("RGB")
_w, _h = _img.size
if _w > TW or _h > TH:
    raise SystemExit(
        f"altair vl-convert produced {_w}×{_h}, exceeds target {TW}×{TH}. "
        f"Shrink chart .properties(width=, height=) values and re-render."
    )
if _w < TW or _h < TH:
    _canvas = Image.new("RGB", (TW, TH), PAGE_BG)
    _canvas.paste(_img, ((TW - _w) // 2, (TH - _h) // 2))
    _canvas.save(f"plot-{THEME}.png")

chart.save(f"plot-{THEME}.html")

Part of Real-Time Dashboard Tiles on anyplot.ai.

Other implementations