Claude
Skills
Sign in
Back

conditional-formatting

Included with Lifetime
$97 forever

Data-driven conditional formatting, live data binding, and dynamic diagram updates for draw.io

General

What this skill does


# Conditional Formatting and Data-Driven Diagrams

## Custom Properties with Object Tags

Wrap `mxCell` in an `<object>` tag to attach arbitrary key-value metadata to any diagram element:

```xml
<object label="Service A" id="2"
        service-id="svc-api-gateway"
        status="healthy"
        latency="45ms"
        uptime="99.97%"
        owner="platform-team"
        environment="production"
        region="us-east-1">
  <mxCell style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;"
          vertex="1" parent="1">
    <mxGeometry x="100" y="100" width="120" height="60" as="geometry"/>
  </mxCell>
</object>
```

Key points:
- `label` replaces `value` as the display text
- `id` moves from `mxCell` to `<object>`
- Any attribute name is valid (use lowercase with hyphens)
- Properties are visible in draw.io's **Edit Data** dialog (Ctrl+M)
- Properties are searchable via **Edit > Find/Replace**

## Placeholder Variables

Display property values dynamically inside labels using `%property%` syntax. Enable with `placeholders=1` in the style:

```xml
<object label="%name%&lt;br&gt;Status: %status%&lt;br&gt;Latency: %latency%"
        id="3" placeholders="1"
        name="API Gateway"
        status="healthy"
        latency="42ms">
  <mxCell style="rounded=1;whiteSpace=wrap;html=1;placeholders=1;fillColor=#dae8fc;strokeColor=#6c8ebf;"
          vertex="1" parent="1">
    <mxGeometry x="100" y="100" width="160" height="80" as="geometry"/>
  </mxCell>
</object>
```

**Rendered label:**
```
API Gateway
Status: healthy
Latency: 42ms
```

### Built-in Placeholders

| Placeholder | Value |
|-------------|-------|
| `%label%` | Cell label |
| `%id%` | Cell ID |
| `%date%` | Current date |
| `%time%` | Current time |
| `%timestamp%` | ISO timestamp |
| `%page%` | Page number |
| `%pagenumber%` | Page number (alias) |
| `%pagecount%` | Total pages |
| `%filename%` | File name |

## File-Level Variables

Set global variables at the `<mxfile>` level, accessible by all cells:

```xml
<mxfile vars='{"env":"production","version":"2.1.0","region":"us-east-1","last_updated":"2026-03-14"}'>
  <diagram id="page1" name="Status Dashboard">
    <mxGraphModel>
      <root>
        <mxCell id="0"/>
        <mxCell id="1" parent="0"/>
        <object label="Environment: %env%&lt;br&gt;Version: %version%&lt;br&gt;Region: %region%"
                id="header" placeholders="1">
          <mxCell style="text;fontSize=14;fontStyle=1;placeholders=1;" vertex="1" parent="1">
            <mxGeometry x="20" y="20" width="300" height="60" as="geometry"/>
          </mxCell>
        </object>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>
```

File-level variables are inherited by all cells that use `placeholders=1` and do not have a local property with the same name.

## Conditional Formatting Rules

### Status to Color Mapping

The most common pattern: map a property value to fill/stroke colors.

| Status | Fill Color | Stroke Color | Icon |
|--------|-----------|-------------|------|
| healthy / up / ok | `#D5E8D4` | `#82B366` | Green |
| warning / degraded | `#FFF2CC` | `#D6B656` | Yellow |
| critical / down / error | `#F8CECC` | `#B85450` | Red |
| maintenance / paused | `#E1D5E7` | `#9673A6` | Purple |
| unknown / pending | `#F5F5F5` | `#666666` | Gray |
| info / active | `#DAE8FC` | `#6C8EBF` | Blue |

### Threshold-Based Color Gradients

Map numeric values to colors using thresholds:

| Metric | Green | Yellow | Red |
|--------|-------|--------|-----|
| Latency | < 100ms | 100-500ms | > 500ms |
| CPU | < 60% | 60-85% | > 85% |
| Error Rate | < 1% | 1-5% | > 5% |
| Uptime | > 99.9% | 99-99.9% | < 99% |
| Disk | < 70% | 70-90% | > 90% |

### Boolean Visibility

Show or hide elements based on boolean properties:

| Condition | Visible Style | Hidden Style |
|-----------|--------------|-------------|
| Feature enabled | `opacity=100;` | `opacity=20;dashed=1;` |
| Service active | Normal styles | `strokeColor=#CCCCCC;fillColor=#F5F5F5;fontColor=#999999;` |
| Deprecated | Normal + label | `dashed=1;dashPattern=8 4;fontStyle=2;` (italic) |

### Enumeration to Shape/Icon

Map state values to different visual representations:

| State | Visual |
|-------|--------|
| running | Green circle icon |
| stopped | Red square icon |
| starting | Yellow spinner icon |
| terminating | Orange triangle icon |

## Python Update Script

Full-featured script that reads a data source and updates diagram XML:

```python
#!/usr/bin/env python3
"""
update_diagram.py - Update draw.io diagram with live data.

Usage:
    python update_diagram.py --input arch.drawio --output arch-live.drawio --data-url https://api.example.com/health
    python update_diagram.py --input arch.drawio --output arch-live.drawio --data-file status.json
"""

import xml.etree.ElementTree as ET
import json
import argparse
import re
import sys
import urllib.request
import urllib.error
import base64
import zlib
from datetime import datetime, timezone


# Status-to-color mapping
STATUS_COLORS = {
    'healthy':     {'fill': '#D5E8D4', 'stroke': '#82B366'},
    'up':          {'fill': '#D5E8D4', 'stroke': '#82B366'},
    'ok':          {'fill': '#D5E8D4', 'stroke': '#82B366'},
    'warning':     {'fill': '#FFF2CC', 'stroke': '#D6B656'},
    'degraded':    {'fill': '#FFF2CC', 'stroke': '#D6B656'},
    'critical':    {'fill': '#F8CECC', 'stroke': '#B85450'},
    'down':        {'fill': '#F8CECC', 'stroke': '#B85450'},
    'error':       {'fill': '#F8CECC', 'stroke': '#B85450'},
    'maintenance': {'fill': '#E1D5E7', 'stroke': '#9673A6'},
    'unknown':     {'fill': '#F5F5F5', 'stroke': '#666666'},
}


def update_style_property(style: str, key: str, value: str) -> str:
    """Update a single property in a draw.io style string."""
    pattern = re.compile(rf'{re.escape(key)}=[^;]*')
    if pattern.search(style):
        style = pattern.sub(f'{key}={value}', style)
    else:
        if not style.endswith(';'):
            style += ';'
        style += f'{key}={value};'
    return style


def get_threshold_color(value: float, thresholds: list) -> dict:
    """
    Determine color based on value thresholds.
    thresholds: list of (max_value, colors_dict) sorted ascending.
    Example: [(100, green), (500, yellow), (float('inf'), red)]
    """
    for threshold, colors in thresholds:
        if value <= threshold:
            return colors
    return thresholds[-1][1]  # fallback to last


def decompress_diagram(compressed: str) -> str:
    """Decompress a draw.io compressed diagram XML string."""
    decoded = base64.b64decode(compressed)
    decompressed = zlib.decompress(decoded, -15)
    return urllib.parse.unquote(decompressed.decode('utf-8'))


def compress_diagram(xml_str: str) -> str:
    """Compress diagram XML back to draw.io compressed format."""
    encoded = urllib.parse.quote(xml_str, safe='')
    compressed = zlib.compress(encoded.encode('utf-8'), 9)
    # Strip zlib header (first 2 bytes) and checksum (last 4 bytes)
    raw = compressed[2:-4]
    return base64.b64encode(raw).decode('utf-8')


def update_diagram(input_path: str, output_path: str, data: dict,
                   compress: bool = False):
    """Update diagram cells based on service data."""
    tree = ET.parse(input_path)
    root = tree.getroot()

    # Handle both mxfile wrapper and bare mxGraphModel
    if root.tag == 'mxfile':
        for diagram_elem in root.findall('diagram'):
            # Check if diagram content is compressed
            text = diagram_elem.text
            if text and text.strip():
                # Compressed format
                xml_str = decompress_diagram(text.strip())
                model = ET.fromstring(xml_str)
                process_model(model, data)
                if compress:
                    diagram_elem.text = compress_diagram(
                        ET.tostring(model, encoding='unicode'))
                else:
                    diagram_elem.text = None
                    diagram_e

Related in General