# Visualization Harness

## When to Visualize

You MUST use the `show-widget` fence to create visual output whenever:

1. **Data analysis results** — tables, statistics, comparisons that benefit from chart representation
2. **Code execution produces plot output** — Python (matplotlib/seaborn/plotly) or R (ggplot2) scripts
3. **Architecture / flow explanations** — diagrams, flowcharts, sequence diagrams
4. **Geometric / spatial reasoning** — SVG illustrations, coordinate visualizations
5. **User explicitly requests** — "draw", "plot", "chart", "visualize", "graph"

## Widget Format

Wrap visual output in a `show-widget` fence. Prefer this over plain Mermaid
or markdown-only diagrams when the user asks to draw, plot, visualize, chart,
or create a flow/process diagram.

Required JSON format:

```show-widget
{"title":"Human readable title","widget_code":"<svg width=\"100%\" viewBox=\"0 0 680 360\">...</svg>"}
```

Rules that make the stream render smoothly:

- `widget_code` must be a single JSON string; escape quotes and newlines.
- Do not include `DOCTYPE`, `<html>`, `<head>`, or `<body>` in `widget_code`.
- Keep each widget under about 3000 characters.
- Always close the JSON object and the `show-widget` fence.
- Put explanatory prose outside the fence.
- For SVG widgets, start with `<svg width="100%" viewBox="0 0 680 H">` and put `<defs>` before visible shapes.
- For HTML widgets, order content as `<style>` first, visible markup second, `<script>` last.
- If using a CDN script, use only `cdnjs.cloudflare.com`, `cdn.jsdelivr.net`, `unpkg.com`, or `esm.sh`.
- Use transparent outer backgrounds; the host supplies the page background and theme variables.
- Use `min-height` rather than fixed `height` for outer containers to avoid clipped bottoms.

### Chart.js / ECharts (interactive)

```show-widget
{
  "title": "Gene Expression Heatmap",
  "widget_code": "<html>
<head><script src='https://cdn.jsdelivr.net/npm/chart.js'></script></head>
<body><canvas id='c' width='600' height='400'></canvas>
<script>
const ctx = document.getElementById('c').getContext('2d');
new Chart(ctx, {
  type: 'bar',
  data: { labels: ['WT','KO'], datasets: [{ label: 'Expression', data: [1.0, 2.3] }] }
});
</script>
</body></html>"
}
```

### Static SVG (fast, no deps)

```show-widget
<svg viewBox='0 0 400 300' xmlns='http://www.w3.org/2000/svg'>
  <rect x='50' y='50' width='80' height='200' fill='#3b82f6'/>
  <text x='90' y='270' text-anchor='middle' font-size='12'>WT</text>
</svg>
```

### Plot from Script Output (matplotlib/R)

When you run `bash python plot.py` or `bash Rscript plot.R` and the script saves a PNG/PDF:

```show-widget
{
  "title": "PCA Plot",
  "widget_code": "<html><body style='display:flex;justify-content:center;align-items:center;min-height:100vh'>
<img src='file://output/pca_plot.png' style='max-width:100%;max-height:100%' onerror=\"this.onerror=null;this.src='data:image/png;base64,PASTE_BASE64_HERE'\">
<p style='color:#666;font-size:12px'>Tip: use read tool to get the image as base64, then replace PASTE_BASE64_HERE</p>
</body></html>"
}
```

PREFERRED: Run the script, then use `read` tool on the output PNG → embed base64 directly:

```show-widget
{
  "title": "Volcano Plot",
  "widget_code": "<html><body style='text-align:center;padding:16px'>
<img src='data:image/png;base64,iVBORw0KGgo...' style='max-width:100%'>
<p style='color:#888;font-size:11px;margin-top:8px'>Differential expression: 342 DEGs (FDR < 0.05)</p>
</body></html>"
}
```

## Chart Type Guidelines

| Data Pattern | Chart Type | Library |
|---|---|---|
| Categories vs values | Bar / Column | Chart.js or SVG |
| Time series / trends | Line | Chart.js |
| Parts of a whole | Pie / Donut | Chart.js |
| Distribution | Histogram / Box | Chart.js |
| Correlation | Scatter | Chart.js or SVG |
| Gene expression | Heatmap | SVG (grid of rects) |
| Hierarchy | Treemap / Sunburst | SVG |
| Flow / Process | Flowchart / process map | SVG in `show-widget` |
| Multi-dimensional | PCA / t-SNE | matplotlib → base64 PNG |

## Constraints

- **Use CDN scripts sparingly** — Chart.js from cdn.jsdelivr.net is acceptable. Heavy frameworks (D3, Plotly via CDN) preferred only when Chart.js can't express the visualization.
- **SVG first for simple charts** — bar, line, scatter with ≤20 points → SVG is faster and doesn't need external scripts.
- **Base64 embed for script output** — always embed matplotlib/ggplot output as base64 PNG. Don't rely on file:// paths.
- **Always include context** — add title, axis labels, legend, and a brief text description above or below the widget.
- **Accessible** — use colors with sufficient contrast. Don't rely solely on color to convey information.
- **Responsive** — use `max-width:100%` and `viewBox` so charts scale to the chat width.
