Skill Plot - Annotation visuelle de plots
Workflow pour annoter des plots matplotlib avec des zones colorées et les modifier par référence.
Commandes
| Commande | Description |
|---|
/plot ou /plot show | Affiche le plot actuel et ses annotations |
/plot load <chemin> | Charge une image et lance l'annotateur |
/plot annotate | Lance l'annotateur HTML |
/plot zones | Liste les annotations par groupe |
/plot apply | Applique les modifications au code source |
/plot list | Liste tous les plots sauvegardés |
Pipeline complet
Étape 1: Charger le plot
bash
1/plot load /chemin/vers/figure.png
Actions:
- Copier l'image vers
~/.claude/plots/current.png
- Chercher le script source automatiquement (grep dans le projet)
- Demander la commande de régénération
- Sauvegarder les métadonnées
- Lancer l'annotateur
Étape 2: Annoter (utilisateur)
L'utilisateur dans le navigateur:
- Zoom/pan pour naviguer
- Dessiner formes + ajouter texte descriptif
- ➕ Nouveau groupe pour séparer les annotations
- 💾 Sauvegarder
Étape 3: Appliquer les modifications
Claude:
- Lit les annotations groupées
- Pour chaque groupe: forme(s) + texte = une modification
- Trouve l'élément matplotlib correspondant
- Modifie le code source
- Régénère le plot
json
1{
2 "zones": [
3 {
4 "id": "blue",
5 "color": "#2196F3",
6 "type": "rect",
7 "group_id": 2,
8 "bbox": [1730, 115, 2266, 300],
9 "label": null
10 },
11 {
12 "id": "blue",
13 "color": "#2196F3",
14 "type": "text",
15 "group_id": 2,
16 "text": "remplacer Dynamic par Updated",
17 "position": [726, 172],
18 "label": null
19 },
20 {
21 "id": "red",
22 "color": "#F44336",
23 "type": "rect",
24 "group_id": 3,
25 "bbox": [197, 1283, 2299, 1487],
26 "label": null
27 },
28 {
29 "id": "red",
30 "color": "#F44336",
31 "type": "text",
32 "group_id": 3,
33 "text": "plus petit labels",
34 "position": [1758, 1490],
35 "label": null
36 }
37 ],
38 "created": "2026-01-22T16:09:51.051Z",
39 "plot_name": "current"
40}
Interprétation:
- Groupe 2 (bleu): Rectangle sur titre/légende + "remplacer Dynamic par Updated"
- Groupe 3 (rouge): Rectangle sur x-axis + "plus petit labels"
Logique de /plot apply
1. Parser les annotations par groupe
python
1# Pseudo-code
2groups = {}
3for zone in annotations["zones"]:
4 gid = zone["group_id"]
5 if gid not in groups:
6 groups[gid] = {"shapes": [], "text": None, "color": zone["id"]}
7 if zone["type"] == "text":
8 groups[gid]["text"] = zone["text"]
9 else:
10 groups[gid]["shapes"].append(zone)
2. Pour chaque groupe, identifier la modification
| Zone (bbox) | Texte | Action matplotlib |
|---|
| Titre (haut centre) | "changer X" | ax.set_title(...) |
| Légende | "modifier label" | ax.legend(...) ou dans plot()/scatter() |
| Axes X (bas) | "plus petit" | ax.tick_params(axis='x', labelsize=...) |
| Axes Y (gauche) | "rotation" | ax.set_ylabel(..., rotation=...) |
| Points scatter | "enlever bordure" | scatter(..., edgecolors='none') |
| Ligne | "changer couleur" | plot(..., color='...') |
3. Mapper bbox → élément du plot
Pour une image 4200×1650:
- Titre: y < 200, x centré
- Légende: souvent coin supérieur droit ou selon
loc=
- X-axis labels: y > 1400 (bas)
- Y-axis labels: x < 200 (gauche)
- Zone données: rectangle central
4. Modifier le code source
- Lire
current_meta.json pour obtenir source_script
- Trouver la fonction/section qui génère le plot
- Appliquer la modification (ex: ajouter
labelsize=8)
- Sauvegarder le fichier
5. Régénérer le plot
bash
1cd {regen_cwd} && {regen_cmd}
Actions détaillées par commande
/plot show
python
1# 1. Afficher l'image
2Read("~/.claude/plots/current.png")
3
4# 2. Lire métadonnées
5meta = Read("~/.claude/plots/current_meta.json")
6
7# 3. Lire annotations
8annotations = Read("~/.claude/plots/current_annotations.json")
9
10# 4. Résumer par groupe
11for group_id, items in group_by(annotations, "group_id"):
12 shapes = [i for i in items if i["type"] != "text"]
13 text = next((i["text"] for i in items if i["type"] == "text"), None)
14 print(f"Groupe {group_id}: {len(shapes)} forme(s), instruction: {text}")
/plot annotate
Lance l'annotateur vide (sans image). L'utilisateur peut drag & drop ou cliquer "current.png".
bash
1fuser -k 8888/tcp 2>/dev/null || true
2sleep 1
3python3 ~/.claude/tools/annotate_server.py &
4sleep 2
5xdg-open "http://localhost:8888/annotate.html" # Sans ?load=true → démarre vide
/plot zones
Lire et afficher current_annotations.json groupé par group_id.
/plot load <chemin>
cp <chemin> ~/.claude/plots/current.png
- Chercher script source:
bash
1# Extraire nom fichier
2filename=$(basename <chemin> .png)
3# Trouver projet root
4project_root=$(git -C $(dirname <chemin>) rev-parse --show-toplevel 2>/dev/null)
5# Chercher dans les .py
6grep -r "$filename" --include="*.py" "$project_root"
- Demander commande regen (AskUserQuestion)
- Sauver métadonnées
- Lancer annotateur avec
?load=true pour charger l'image automatiquement:
bash
1fuser -k 8888/tcp 2>/dev/null || true
2sleep 1
3python3 ~/.claude/tools/annotate_server.py &
4sleep 2
5xdg-open "http://localhost:8888/annotate.html?load=true"
/plot apply
IMPORTANT: Suivre cette logique exacte avec CONFIRMATION OBLIGATOIRE:
-
Lire les fichiers
annotations = ~/.claude/plots/current_annotations.json
meta = ~/.claude/plots/current_meta.json
-
Grouper les annotations
Pour chaque group_id unique:
- Collecter les formes (rect, circle, line)
- Extraire le texte (instruction)
-
Pour chaque groupe, analyser:
- Où pointe la forme? (bbox → élément matplotlib)
- Que demande le texte? (instruction)
-
Lire le code source (meta.source_script)
-
AFFICHER UN RÉSUMÉ DÉTAILLÉ (NE PAS MODIFIER ENCORE!)
markdown
1## Modifications proposées
2
3**Fichier:** `/chemin/vers/script.py`
4
5### Groupe X (couleur):
6- **Zone ciblée:** [description de l'élément, ex: "Titre principal", "Légende", "Labels axe X"]
7- **Instruction:** "texte de l'annotation"
8- **Modification proposée:**
9 - Ligne ~XX: `ancien_code`
10 - Devient: `nouveau_code`
11
12### Groupe Y (couleur):
13- **Zone ciblée:** ...
14- **Instruction:** ...
15- **Modification proposée:** ...
16
17---
18**Confirmer ces modifications?** (oui/non)
-
ATTENDRE LA CONFIRMATION EXPLICITE
- Si "oui" → procéder aux modifications
- Si "non" → demander ce qui doit être ajusté
- NE JAMAIS modifier le code sans confirmation!
-
Appliquer les modifications (seulement après confirmation)
-
Régénérer si regen_cmd disponible
Contrôles de l'annotateur
| Action | Contrôle |
|---|
| Zoom | Molette souris |
| Pan | Espace+drag, Clic-droit+drag, ou bouton ✋ |
| Dessiner | Choisir outil (rect/circle/line/freedraw/text) |
| Texte | Outil 📝 + clic → modal stylée (Enter=OK, Esc=annuler) |
| Nouveau groupe | Bouton ➕ (sépare les annotations) |
| Labels | Bouton 🏷️ → panneau latéral |
| Sauvegarder | Bouton 💾 (auto-save sur disque) |
| Supprimer | Sélection + Delete |
Fichiers
| Fichier | Contenu |
|---|
~/.claude/plots/current.png | Plot actuel (sauvegardé auto quand user drop + save) |
~/.claude/plots/current_annotated.png | Plot avec annotations visuelles |
~/.claude/plots/current_meta.json | Métadonnées (source_script détecté auto) |
~/.claude/plots/current_annotations.json | Zones annotées avec group_id |
~/.claude/tools/annotate.html | App HTML (Fabric.js) |
~/.claude/tools/annotate_server.py | Serveur Python (port 8888) |
Détection automatique
Quand l'utilisateur drop une image dans l'annotateur et clique Save:
- L'image de fond →
current.png
- Le nom du fichier est envoyé au serveur
- Le serveur cherche dans les projets connus (
grep -r "filename" --include="*.py")
- Si trouvé →
current_meta.json est mis à jour avec source_script
Projets scannés:
- Dossiers des précédents
/plot load
~/Github, /media/*/Data/Github
Couleurs disponibles
| Couleur | Hex | Usage suggéré |
|---|
| blue | #2196F3 | Annotations principales |
| red | #F44336 | Erreurs, suppressions |
| green | #4CAF50 | Validations, OK |
| yellow | #FFEB3B | Attention, warnings |
| orange | #FF9800 | Modifications secondaires |
| purple | #9C27B0 | Notes spéciales |
Exemple complet
Utilisateur: /plot load /media/data/outputs/fig_trends.png
Claude: Plot chargé.
- Source: /media/data/scripts/plot_trends.py
- Commande regen: python scripts/plot_trends.py --output outputs/
- Annotateur: http://localhost:8888/annotate.html
[Utilisateur annote: rect bleu sur légende + texte "Dynamic → Updated"]
[Utilisateur annote: rect rouge sur x-axis + texte "smaller font"]
[Utilisateur clique 💾]
Utilisateur: /plot apply
Claude: J'ai analysé 2 groupes d'annotations. Voici les modifications proposées:
---
## Modifications proposées
**Fichier:** `/media/data/scripts/plot_trends.py`
### Groupe 2 (bleu) - Légende
- **Zone ciblée:** Légende (bbox: 2491,1146 → 3054,1301)
- **Instruction:** "Dynamic → Updated"
- **Modification proposée:**
- Ligne 45: `label='Dynamic (Sentinel-2)'`
- Devient: `label='Updated (Sentinel-2)'`
### Groupe 3 (rouge) - Labels axe X
- **Zone ciblée:** Labels axe X (bbox: 197,1283 → 2299,1487)
- **Instruction:** "smaller font"
- **Modification proposée:**
- Ajouter après ligne 52: `ax.tick_params(axis='x', labelsize=8)`
---
**Confirmer ces modifications?** (oui/non)
Utilisateur: oui
Claude: Modifications appliquées ✓
- Ligne 45: label mis à jour
- Ligne 53: tick_params ajouté
Régénération du plot...
[Commande exécutée]
✅ Nouveau plot généré. Voici le résultat:
[Affiche le nouveau plot]