A visual annotation tool for matplotlib plots, designed to work with Claude Code and Codex CLI. Draw shapes, add text instructions, and let AI modify your code automatically.
Use case: Annotate a plot visually → AI reads annotations → AI modifies your matplotlib code → Confirm before applying
- Pan & Zoom - Navigate large plots like Google Maps
- Mouse wheel to zoom in/out
- Space + drag or Right-click + drag to pan
- Drawing Tools - Rectangle, Circle, Line, Freehand, Text
- Color-coded Zones - 6 colors to categorize annotations
- Group System - Group shapes + text for multi-part modifications
- Refresh from Source - Reload the original file after regenerating your plot
- Labels Panel - Add descriptions per color zone
- Auto-save - Annotations saved directly to disk (JSON + annotated PNG)
- No dependencies - Pure HTML/JS frontend (Fabric.js via CDN)
- Cross-platform - Works on Linux, macOS, Windows
# Clone the repo
git clone https://github.com/tofunori/plot-annotator.git
cd plot-annotator
# Start the server
python3 annotate_server.py
# Open in browser
# http://localhost:8888/annotate.htmlThen drag & drop your plot image onto the canvas.
| Action | Control |
|---|---|
| Zoom | Mouse wheel |
| Pan | Space + drag, Right-click + drag, or Pan button |
| Draw | Select tool → click & drag |
| Add Text | Text tool → click → type in modal |
| New Group | ➕ button (groups shapes + text together) |
| Refresh | 🔃 button (reload from source after regenerating) |
| Labels | 🏷️ button → side panel |
| Save | 💾 button (auto-saves to disk) |
| Delete | Select object → Delete key |
The refresh button 🔃 allows you to reload your plot after modifying the source script:
- Open your plot image
- Annotate with shapes and text
- Modify your Python script and regenerate the plot
- Click 🔃 to reload the updated image (annotations preserved)
The server automatically finds the file by name in common directories (~/Github, /media/*/Data, etc.).
When you save, files are created in ~/.claude/plots/:
| File | Description |
|---|---|
current.png |
Current plot image |
current_annotated.png |
Image with annotations drawn |
current_annotations.json |
Annotation coordinates and metadata |
current_meta.json |
Source file path and script info |
{
"zones": [
{
"id": "blue",
"color": "#2196F3",
"type": "rect",
"group_id": 1,
"bbox": [100, 50, 300, 150],
"label": null
},
{
"id": "blue",
"color": "#2196F3",
"type": "text",
"group_id": 1,
"text": "Change title to French",
"position": [120, 80],
"label": null
}
],
"created": "2026-01-22T10:00:00.000Z",
"plot_name": "current"
}Group interpretation: Shapes and text with the same group_id form a single modification request.
The main use case with Claude Code or Codex CLI:
- Load your matplotlib figure
- Annotate visually: draw shape + write instruction
- AI analyzes annotations and proposes code changes
- You confirm → code is modified → plot regenerated
Use the refresh button 🔃 to iterate quickly:
- Annotate changes needed
- AI modifies code and regenerates
- Click 🔃 to see the new plot (annotations preserved)
- Add more annotations if needed
- Repeat until perfect
Share annotated plots with colleagues or AI assistants for feedback.
python3 annotate_server.pyServes files from ~/.claude/plots/ on port 8888.
# Edit PLOTS_DIR in annotate_server.py
PLOTS_DIR = Path("/your/custom/path")Open annotate.html directly in browser. Note: auto-save and refresh won't work without the server.
| Endpoint | Method | Description |
|---|---|---|
/save |
POST | Save annotations JSON |
/save-image |
POST | Save annotated PNG |
/refresh-from-source |
POST | Reload from original file path |
/refresh-by-filename |
POST | Search and reload by filename |
/set-source-path |
POST | Manually set source path |
/search-script |
POST | Find Python script that generates the plot |
| Color | Hex | Use for |
|---|---|---|
| Blue | #2196F3 | Primary annotations |
| Red | #F44336 | Issues, deletions |
| Green | #4CAF50 | Approved, correct |
| Yellow | #FFEB3B | Warnings, attention |
| Orange | #FF9800 | Secondary changes |
| Purple | #9C27B0 | Special notes |
- Python 3.6+ (for server)
- Modern browser (Chrome, Firefox, Safari, Edge)
- No pip dependencies!
This tool is designed to work with:
- Claude Code - Anthropic's CLI for Claude
- Codex CLI - OpenAI's coding assistant
Copy the skills/ folder to your skills directory:
# For Claude Code
cp -r skills/plot ~/.claude/skills/
# For Codex CLI
cp -r skills/plot ~/.codex/skills/# Load a plot
/plot load /path/to/figure.png
# Annotate in browser:
# - Draw rectangle around element to modify
# - Add text with instruction (same group)
# - Click 💾 Save
# Apply changes
/plot apply
# → AI shows proposed modifications with exact code changes
# → You confirm (oui/non) before any code is modified
# → Plot is regenerated automaticallyInstead of describing changes in text ("make the x-axis labels smaller"), you:
- Draw a rectangle around the x-axis labels
- Write "smaller font" as text annotation
- AI sees exactly what you're pointing at
- AI proposes the exact code change
- You confirm before anything is modified
| Browser | File Picker Refresh | Drag & Drop Refresh |
|---|---|---|
| Chrome/Edge | ✅ Native | ✅ Native |
| Firefox/Zen | ✅ Auto-search | ✅ Auto-search |
Firefox users: The server automatically searches for files by name since Firefox doesn't support the File System Access API.
MIT License - Feel free to use, modify, and distribute.
PRs welcome! Ideas for improvements:
- Undo/redo support
- Arrow tool
- Export to SVG
- Multiple pages/plots
- Annotation templates
Built with Fabric.js for canvas manipulation.
