Claude Code skill for publication-quality scientific visualisations: chart, architecture, flowchart, comparison, pipeline. Bundles matplotlib publication defaults (300 DPI, serif font, colorblind palette), NADEZHDA project palette, Mermaid conventions, and ready-to-use templates. Contents: - SKILL.md — behaviour spec (5 types, generation pipeline) - README.md — human-facing entry: when, install, examples - reference/chart_patterns.md — Pareto/bar/radar/heatmap snippets - templates/architecture_nadezhda.md — Mermaid templates for Teacher-Student / LUPI / fusion Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.6 KiB
5.6 KiB
Шаблоны визуализаций для CVGL
1. Pareto Front: Params vs R@1
import matplotlib.pyplot as plt
import numpy as np
methods = {
'Sample4Geo': (88.5, 92.65),
'VimGeo': (50.87, 96.19),
'QDFL': (5.0, 95.00),
'MobileGeo': (28.57, 97.15),
'(MGS)²': (100.0, 97.50),
'NADEZHDA': (8.5, None), # target
}
fig, ax = plt.subplots(figsize=(8, 5))
for name, (params, r1) in methods.items():
if r1 is None:
ax.scatter(params, 90, marker='*', s=200, c='#ff7f0e', zorder=5)
ax.annotate(f'{name}\n(target)', (params, 90), fontsize=9, ha='center', va='bottom')
else:
ax.scatter(params, r1, s=100, zorder=4)
ax.annotate(name, (params, r1), fontsize=9, textcoords='offset points', xytext=(5, 5))
ax.set_xlabel('Parameters (M)')
ax.set_ylabel('R@1 (%) on University-1652')
ax.set_title('Accuracy vs Model Size: CVGL Methods')
ax.axvspan(0, 10, alpha=0.1, color='green', label='Edge budget (≤10M)')
ax.legend()
plt.savefig('pareto_params_r1.png', dpi=300, bbox_inches='tight')
plt.savefig('pareto_params_r1.pdf', bbox_inches='tight')
2. Grouped Bar: R@1 Across Datasets
import matplotlib.pyplot as plt
import numpy as np
methods = ['Sample4Geo', 'VimGeo', 'GeoDTR+', 'CAMP', 'CGSI']
datasets = ['Univ-1652', 'CVUSA', 'CVACT-test']
data = np.array([
[92.65, 98.68, 75.0], # Sample4Geo
[0, 96.19, 81.69], # VimGeo
[94.67, 95.43, 0], # GeoDTR+
[94.46, 98.97, 0], # CAMP
[95.45, 0, 0], # CGSI
])
x = np.arange(len(methods))
width = 0.25
fig, ax = plt.subplots(figsize=(10, 5))
for i, ds in enumerate(datasets):
mask = data[:, i] > 0
bars = ax.bar(x[mask] + i * width, data[mask, i], width, label=ds)
ax.set_ylabel('R@1 (%)')
ax.set_xticks(x + width)
ax.set_xticklabels(methods, rotation=15, ha='right')
ax.legend()
ax.set_ylim(70, 102)
plt.savefig('r1_comparison.png', dpi=300, bbox_inches='tight')
3. Training Curve with Loss Components
import matplotlib.pyplot as plt
import numpy as np
epochs = np.arange(60)
# Simulated progressive staging
l_task = 1.5 * np.exp(-0.03 * epochs) + 0.2
l_lupi = np.where(epochs < 10, 0, np.where(epochs < 20,
0.5 * (epochs - 10) / 10, 0.5)) * np.exp(-0.02 * (epochs - 10).clip(0))
l_feat = np.where(epochs < 10, 0, 0.3 * np.exp(-0.02 * (epochs - 10)))
l_total = l_task + l_lupi + l_feat
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(epochs, l_task, label='$L_{task}$ (InfoNCE)', linewidth=2)
ax.plot(epochs, l_lupi, label='$L_{LUPI}$ (MSE)', linewidth=2, linestyle='--')
ax.plot(epochs, l_feat, label='$L_{feat}$ (alignment)', linewidth=2, linestyle=':')
ax.plot(epochs, l_total, label='$L_{total}$', linewidth=2.5, color='black', alpha=0.7)
ax.axvspan(0, 10, alpha=0.08, color='blue', label='Warmup')
ax.axvspan(10, 20, alpha=0.08, color='orange', label='Ramp-up')
ax.axvspan(20, 60, alpha=0.05, color='green', label='Full')
ax.set_xlabel('Epoch')
ax.set_ylabel('Loss')
ax.set_title('Progressive Loss Staging (NADEZHDA)')
ax.legend(ncol=2, fontsize=9)
plt.savefig('training_curve.png', dpi=300, bbox_inches='tight')
4. Architecture Block Diagram (matplotlib patches)
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
fig, ax = plt.subplots(figsize=(14, 6))
ax.set_xlim(0, 14)
ax.set_ylim(0, 6)
ax.axis('off')
def add_block(ax, xy, w, h, label, color, sublabel=''):
box = mpatches.FancyBboxPatch(xy, w, h, boxstyle='round,pad=0.1',
facecolor=color, edgecolor='black', linewidth=1.5, alpha=0.85)
ax.add_patch(box)
ax.text(xy[0] + w/2, xy[1] + h/2, label, ha='center', va='center',
fontsize=10, fontweight='bold')
if sublabel:
ax.text(xy[0] + w/2, xy[1] + 0.15, sublabel, ha='center', va='bottom',
fontsize=7, color='gray')
def add_arrow(ax, start, end, label=''):
ax.annotate('', xy=end, xytext=start,
arrowprops=dict(arrowstyle='->', lw=1.5, color='#333'))
if label:
mid = ((start[0]+end[0])/2, (start[1]+end[1])/2 + 0.15)
ax.text(*mid, label, fontsize=7, ha='center', color='#555')
# Teacher side
add_block(ax, (0.5, 4), 2, 1.2, 'DINOv2-L\n(frozen+LoRA)', '#1f77b4', '304M params')
add_block(ax, (0.5, 2), 2, 1.2, 'Multi-FiLM\nFusion', '#9467bd', 'text→visual modulation')
add_block(ax, (0.5, 0.3), 2, 1.2, 'Teacher\nDescriptor', '#1f77b4', '512-dim')
# Student side
add_block(ax, (5, 4), 2, 1.2, 'FastViT-T12\n(shared)', '#ff7f0e', '8.5M params')
add_block(ax, (5, 0.3), 2, 1.2, 'Student\nDescriptor', '#ff7f0e', '512-dim')
# Distillation arrows
add_arrow(ax, (2.5, 0.9), (5, 0.9), '$L_{LUPI}$')
add_arrow(ax, (2.5, 4.6), (5, 4.6), '$L_{feat}$')
ax.set_title('NADEZHDA: Teacher-Student Architecture', fontsize=14, fontweight='bold')
plt.savefig('nadezhda_architecture.png', dpi=300, bbox_inches='tight')
5. Mermaid: LUPI Distillation Pipeline
```mermaid
graph LR
subgraph Teacher ["Teacher (356M, cloud)"]
S1[Satellite RGB] --> TE[DINOv2-L + LoRA]
D1[Drone RGB] --> TE
SV[Street-View] --> TE
DP[Depth Map] --> TE
TX[Text Desc.] --> FM[Multi-FiLM]
FM --> TE
TE --> TD[Teacher Descriptor 512-dim]
end
subgraph Student ["Student (8.5M, edge)"]
S2[Satellite RGB] --> SE[FastViT-T12]
D2[Drone RGB] --> SE
SE --> SD[Student Descriptor 512-dim]
end
TD -->|L_LUPI: MSE| SD
TE -->|L_feat: Conv1x1 proj| SE
TD -->|L_RKD: relational| SD
style Teacher fill:#e3f2fd,stroke:#1565c0
style Student fill:#fff3e0,stroke:#e65100
```