
Figure Generation
- 1.7k installs
- 255 repo stars
- Updated February 27, 2026
- lingzhi227/agent-research-skills
figure-generation is an agent skill that generate publication-quality scientific figures using matplotlib/seaborn with a three-phase pipeline (query expansion, code generation with execution, vlm visual feedback). handle
About
figure-generation is an agent skill from lingzhi227/agent-research-skills that generate publication-quality scientific figures using matplotlib/seaborn with a three-phase pipeline (query expansion, code generation with execution, vlm visual feedback). handles bar charts, line pl. # Scientific Figure Generation Generate publication-quality figures for research papers. ## Input - `$0` — Description of the desired figure - `$1` — (Optional) Path to data file (CSV, JSON, NPY, PKL) or results directory ## Scripts ### Generate figure template ```bash python ~/.claude/skills/figure-generation/scripts/figure_template.py --type Developers invoke figure-generation during idea/research work for documentation tasks. The skill documents triggers, prerequisites, and step-by-step workflows grounded in SKILL.md. Compatible with Claude Code, Cursor, and Codex agent runtimes that load marketplace skills. Review the Security Audits panel on this listing before installing in production environments.
- Scientific Figure Generation
- Generate publication-quality figures for research papers.
- `$0` — Description of the desired figure
- `$1` — (Optional) Path to data file (CSV, JSON, NPY, PKL) or results directory
- python ~/.claude/skills/figure-generation/scripts/figure_template.py --type bar --output figure_script.py --name compari
Figure Generation by the numbers
- 1,709 all-time installs (skills.sh)
- +51 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #195 of 1,879 Documentation skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
figure-generation capabilities & compatibility
- Capabilities
- scientific figure generation · generate publication quality figures for researc · `$0` — description of the desired figure · `$1` — (optional) path to data file (csv, json, · python ~/.claude/skills/figure generation/script
- Use cases
- orchestration
What figure-generation says it does
Generate publication-quality figures for research papers.
- `$0` — Description of the desired figure
- `$1` — (Optional) Path to data file (CSV, JSON, NPY, PKL) or results directory
npx skills add https://github.com/lingzhi227/agent-research-skills --skill figure-generationAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.7k |
|---|---|
| repo stars | ★ 255 |
| Security audit | 2 / 3 scanners passed |
| Last updated | February 27, 2026 |
| Repository | lingzhi227/agent-research-skills ↗ |
What it does
Generate publication-quality scientific figures using matplotlib/seaborn with a three-phase pipeline (query expansion, code generation with execution, VLM visual feedback). Handles bar charts, line pl
Who is it for?
Developers working on documentation during idea tasks.
Skip if: Tasks outside Documentation scope described in SKILL.md.
When should I use this skill?
Generate publication-quality scientific figures using matplotlib/seaborn with a three-phase pipeline (query expansion, code generation with execution, VLM visual feedback). Handles bar charts, line pl
What you get
Completed documentation workflow aligned with SKILL.md steps.
- Python plotting scripts
- publication-ready PNG figures
Files
Scientific Figure Generation
Generate publication-quality figures for research papers.
Input
$0— Description of the desired figure$1— (Optional) Path to data file (CSV, JSON, NPY, PKL) or results directory
Scripts
Generate figure template
python ~/.claude/skills/figure-generation/scripts/figure_template.py --type bar --output figure_script.py --name comparison
python ~/.claude/skills/figure-generation/scripts/figure_template.py --list-typesAvailable types: bar, training-curve, heatmap, ablation, line, scatter, radar, violin, tsne, attention
Three-Phase Pipeline (from MatPlotAgent)
Phase 1: Query Expansion
Expand the user's figure description into step-by-step coding specifications using the prompts in references/figure-prompts.md. Determine: figure type, data mapping (x/y/color/hue), style requirements, paper conventions.
Phase 2: Code Generation with Execution Loop (up to 4 retries)
1. Generate a self-contained Python script using the template from scripts/figure_template.py as a starting point 2. Write script to a temp file and execute: python figure_script.py 3. If error: capture traceback, feed back, regenerate (see ERROR_PROMPT in references) 4. If no .png produced: add explicit save instruction, retry 5. On success: report the generated figure path
Phase 3: Visual Refinement
Read the generated PNG file and visually inspect using the VLM feedback prompts from references/figure-prompts.md:
- Does the figure type match the request?
- Are labels, titles, and legends correct?
- Is the color scheme appropriate and consistent?
- Are axis scales sensible? Is text readable at publication size?
If improvements needed: generate corrective instructions and re-execute.
References
- All MatPlotAgent prompts:
~/.claude/skills/figure-generation/references/figure-prompts.md - Figure templates:
~/.claude/skills/figure-generation/scripts/figure_template.py
Output
Both PNG (preview, 300 DPI) and PDF (vector, for paper) formats. Plus the LaTeX include code:
\begin{figure}[t]
\centering
\includegraphics[width=\linewidth]{figures/figure_name.pdf}
\caption{Description. Best viewed in color.}
\label{fig:figure_name}
\end{figure}Quality Requirements
- DPI ≥ 300, or vector PDF
- Colorblind-friendly palette (no red-green only)
- All text ≥ 8pt at print size
- Consistent styling across all paper figures
- No matplotlib default title — use LaTeX caption
Related Skills
- Upstream: data-analysis, experiment-code
- Downstream: paper-writing-section, paper-compilation, slide-generation
- See also: table-generation
Figure Generation Prompts
Extracted verbatim from MatPlotAgent.
Query Expansion Agent
System Prompt
According to the user query, expand and solidify the query into a step by step detailed instruction (or comment) on how to write python code to fulfill the user query's requirements. Import the appropriate libraries. Pinpoint the correct library functions to call and set each parameter in every function call accordingly.User Prompt
Here is the user query: [User Query]:
"""
{query}
"""
You should understand what the query's requirements are, and output step by step, detailed instructions on how to use python code to fulfill these requirements. Include what libraries to import, what library functions to call, how to set the parameters in each function correctly, how to prepare the data, how to manipulate the data so that it becomes appropriate for later functions to call etc,. Make sure the code to be executable and correctly generate the desired output in the user query.Plot Agent — Initial Code Generation
System Prompt
You are a cutting-edge super capable code generation LLM. You will be given a natural language query, generate a runnable python code to satisfy all the requirements in the query. You can use any python library you want. When you complete a plot, remember to save it to a png file.User Prompt
Here is the query:
"""
{query}
"""
If the query requires data manipulation from a csv file, process the data from the csv file and draw the plot in one piece of code.
When you complete a plot, remember to save it to a png file. The file name should be """{file_name}""".Plot Agent — Visual Refinement Code Generation
System Prompt
You are a cutting-edge super capable code generation LLM. You will be given a piece of code and natural language instruction on how to improve it. Base on the given code, generate a runnable python code to satisfy all the requirements in the instruction while retaining the original code's functionality. You can use any python library you want. When you complete a plot, remember to save it to a png file.Visual Refine Agent (VLM Feedback)
System Prompt
Given a piece of code, a user query, and an image of the current plot, please determine whether the plot has faithfully followed the user query. Your task is to provide instruction to make sure the plot has strictly completed the requirements of the query. Please output a detailed step by step instruction on how to use python code to enhance the plot.User Prompt
Here is the code: [Code]:
"""
{code}
"""
Here is the user query: [Query]:
"""
{query}
"""
Carefully read and analyze the user query to understand the specific requirements. Examine the provided Python code to understand how the current plot is generated. Check if the code aligns with the user query in terms of data selection, plot type, and any specific customization. Look at the provided image of the plot. Assess the plot type, the data it represents, labels, titles, colors, and any other visual elements. Compare these elements with the requirements specified in the user query. Note any differences between the user query requirements and the current plot. Based on the identified discrepancies, provide step-by-step instructions on how to modify the Python code to meet the user query requirements. Suggest improvements for better visualization practices, such as clarity, readability, and aesthetics, while ensuring the primary focus is on meeting the user's specified requirements.Error Feedback
There are some errors in the code you gave:
{error_message}
please correct the errors.
Then give the complete code and don't omit anything even though you have given it in the above code.GPT-4V Evaluation Prompt (for quality scoring)
You are an excellent judge at evaluating visualization plots between a model generated plot and the ground truth. You will be giving scores on how well it matches the ground truth plot.
The generated plot will be given to you as the first figure. If the first figure is blank, that means the code failed to generate a figure.
Another plot will be given to you as the second figure, which is the desired outcome of the user query, meaning it is the ground truth for you to reference.
Please compare the two figures head to head and rate them.
Suppose the second figure has a score of 100, rate the first figure on a scale from 0 to 100.#!/usr/bin/env python3
"""Generate publication-quality figure templates for academic papers.
Outputs a self-contained Python script ready to be customized.
Supported figure types:
bar, training-curve, heatmap, ablation, line, scatter,
radar, violin, tsne, attention
Usage:
python figure_template.py --type bar --output figure_script.py
python figure_template.py --type training-curve --output figure_script.py
python figure_template.py --type heatmap --output figure_script.py
python figure_template.py --type ablation --output figure_script.py
python figure_template.py --type radar --output figure_script.py
python figure_template.py --type violin --output figure_script.py
python figure_template.py --type tsne --output figure_script.py
python figure_template.py --type attention --output figure_script.py
python figure_template.py --list-types
"""
import argparse
import sys
PREAMBLE = '''import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
# Publication-quality styling
plt.rcParams.update({
'font.family': 'serif',
'font.serif': ['Times New Roman', 'DejaVu Serif'],
'font.size': 11,
'axes.labelsize': 12,
'axes.titlesize': 13,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'figure.dpi': 300,
'savefig.dpi': 300,
'savefig.bbox': 'tight',
'savefig.pad_inches': 0.05,
'axes.grid': True,
'grid.alpha': 0.3,
'axes.spines.top': False,
'axes.spines.right': False,
})
# Colorblind-friendly palette
COLORS = ['#2196F3', '#FF5722', '#4CAF50', '#FFC107', '#9C27B0', '#607D8B', '#E91E63', '#00BCD4']
'''
TEMPLATES = {
"bar": PREAMBLE + '''
# === Baseline Comparison Bar Chart ===
fig, ax = plt.subplots(figsize=(7, 4.5))
methods = ['Ours', 'Baseline A', 'Baseline B', 'Baseline C']
scores = [92.3, 88.1, 85.7, 83.2]
errors = [0.5, 0.8, 1.2, 0.9]
bars = ax.bar(methods, scores, yerr=errors, capsize=5,
color=[COLORS[0]] + [COLORS[5]] * 3,
edgecolor='white', linewidth=0.5)
ax.set_ylabel('Accuracy (%)')
for bar, score in zip(bars, scores):
ax.text(bar.get_x() + bar.get_width()/2., bar.get_height() + 0.8,
f'{score:.1f}', ha='center', va='bottom', fontsize=9)
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"training-curve": PREAMBLE + '''
# === Training Curves (Loss + Accuracy) ===
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
epochs = np.arange(1, 51)
# Replace with actual data
train_loss = 2.0 * np.exp(-0.05 * epochs) + 0.3 + np.random.normal(0, 0.02, len(epochs))
val_loss = 2.2 * np.exp(-0.04 * epochs) + 0.4 + np.random.normal(0, 0.03, len(epochs))
train_acc = 100 * (1 - np.exp(-0.06 * epochs)) + np.random.normal(0, 0.5, len(epochs))
val_acc = 95 * (1 - np.exp(-0.05 * epochs)) + np.random.normal(0, 0.8, len(epochs))
ax1.plot(epochs, train_loss, label='Train', color=COLORS[0], linewidth=1.5)
ax1.plot(epochs, val_loss, label='Validation', color=COLORS[1], linewidth=1.5, linestyle='--')
ax1.set_xlabel('Epoch')
ax1.set_ylabel('Loss')
ax1.legend()
ax1.set_title('Training Loss')
ax2.plot(epochs, train_acc, label='Train', color=COLORS[0], linewidth=1.5)
ax2.plot(epochs, val_acc, label='Validation', color=COLORS[1], linewidth=1.5, linestyle='--')
ax2.set_xlabel('Epoch')
ax2.set_ylabel('Accuracy (%)')
ax2.legend()
ax2.set_title('Accuracy')
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"heatmap": PREAMBLE + '''
import seaborn as sns
# === Heatmap / Confusion Matrix ===
fig, ax = plt.subplots(figsize=(6, 5))
# Replace with actual data
class_names = ['Cat', 'Dog', 'Bird', 'Fish']
data = np.array([[45, 3, 2, 0], [4, 42, 1, 3], [1, 2, 44, 3], [0, 1, 2, 47]])
sns.heatmap(data, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names, yticklabels=class_names,
ax=ax, square=True, linewidths=0.5)
ax.set_xlabel('Predicted')
ax.set_ylabel('True')
ax.set_title('Confusion Matrix')
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"ablation": PREAMBLE + '''
# === Ablation Study Grouped Bar Chart ===
fig, ax = plt.subplots(figsize=(8, 4.5))
datasets = ['Dataset A', 'Dataset B', 'Dataset C']
ablation_results = {
'Full Model': [92.3, 89.1, 91.5],
'w/o Component A': [88.7, 85.3, 87.2],
'w/o Component B': [90.1, 87.5, 89.8],
'w/o Component C': [86.4, 83.1, 85.0],
}
x = np.arange(len(datasets))
width = 0.18
for i, (method, scores) in enumerate(ablation_results.items()):
offset = (i - len(ablation_results) / 2 + 0.5) * width
bars = ax.bar(x + offset, scores, width, label=method, color=COLORS[i])
ax.set_ylabel('Accuracy (%)')
ax.set_xticks(x)
ax.set_xticklabels(datasets)
ax.legend(loc='upper right', fontsize=9)
ax.set_ylim(80, 95)
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"line": PREAMBLE + '''
# === Multi-Line Comparison Plot ===
fig, ax = plt.subplots(figsize=(7, 4.5))
x = np.linspace(0, 10, 50)
methods = {
'Ours': np.sin(x) * 0.9 + 0.1,
'Baseline A': np.sin(x) * 0.7 + 0.1,
'Baseline B': np.sin(x) * 0.5 + 0.1,
}
markers = ['o', 's', '^']
for (name, y), color, marker in zip(methods.items(), COLORS, markers):
ax.plot(x, y, label=name, color=color, linewidth=1.5,
marker=marker, markevery=5, markersize=5)
ax.set_xlabel('X Axis Label')
ax.set_ylabel('Y Axis Label')
ax.legend()
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"scatter": PREAMBLE + '''
# === Scatter Plot with Regression Line ===
fig, ax = plt.subplots(figsize=(6, 5))
np.random.seed(42)
x = np.random.randn(100)
y = 0.8 * x + 0.3 + np.random.randn(100) * 0.3
ax.scatter(x, y, c=COLORS[0], alpha=0.6, s=30, edgecolors='white', linewidth=0.5)
# Regression line
m, b = np.polyfit(x, y, 1)
ax.plot(x, m*x + b, color=COLORS[1], linewidth=2, linestyle='--', label=f'y = {m:.2f}x + {b:.2f}')
ax.set_xlabel('X Variable')
ax.set_ylabel('Y Variable')
ax.legend()
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"radar": PREAMBLE + '''
# === Radar / Spider Chart (Multi-Metric Comparison) ===
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
categories = ['Accuracy', 'Precision', 'Recall', 'F1', 'Speed', 'Memory']
N = len(categories)
methods = {
'Ours': [92, 91, 93, 92, 85, 78],
'Baseline A': [88, 85, 90, 87, 90, 85],
'Baseline B': [85, 82, 88, 84, 95, 92],
}
angles = [n / float(N) * 2 * np.pi for n in range(N)]
angles += angles[:1]
for i, (name, values) in enumerate(methods.items()):
values += values[:1]
ax.plot(angles, values, 'o-', linewidth=1.5, label=name, color=COLORS[i])
ax.fill(angles, values, alpha=0.1, color=COLORS[i])
ax.set_xticks(angles[:-1])
ax.set_xticklabels(categories, size=10)
ax.set_ylim(70, 100)
ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1.1))
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"violin": PREAMBLE + '''
# === Violin Plot (Distribution Comparison) ===
fig, ax = plt.subplots(figsize=(8, 5))
np.random.seed(42)
data = {
'Ours': np.random.normal(92, 2, 100),
'Baseline A': np.random.normal(88, 3, 100),
'Baseline B': np.random.normal(85, 4, 100),
}
positions = range(len(data))
parts = ax.violinplot([v for v in data.values()], positions=positions,
showmeans=True, showmedians=True)
for i, pc in enumerate(parts['bodies']):
pc.set_facecolor(COLORS[i])
pc.set_alpha(0.7)
parts['cmeans'].set_color('black')
parts['cmedians'].set_color('red')
ax.set_xticks(positions)
ax.set_xticklabels(list(data.keys()))
ax.set_ylabel('Accuracy (%)')
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"tsne": PREAMBLE + '''
from sklearn.manifold import TSNE
# === t-SNE Embedding Visualization ===
fig, ax = plt.subplots(figsize=(7, 6))
np.random.seed(42)
n_samples = 200
n_classes = 4
class_names = ['Class A', 'Class B', 'Class C', 'Class D']
# Generate sample embeddings (replace with your actual embeddings)
embeddings = np.vstack([
np.random.randn(n_samples, 64) + i * 2 for i in range(n_classes)
])
labels = np.repeat(range(n_classes), n_samples)
tsne = TSNE(n_components=2, random_state=42, perplexity=30)
coords = tsne.fit_transform(embeddings)
for i in range(n_classes):
mask = labels == i
ax.scatter(coords[mask, 0], coords[mask, 1], c=COLORS[i],
label=class_names[i], alpha=0.6, s=15, edgecolors='white', linewidth=0.3)
ax.set_xlabel('t-SNE dim 1')
ax.set_ylabel('t-SNE dim 2')
ax.legend(markerscale=2)
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
"attention": PREAMBLE + '''
import seaborn as sns
# === Attention Heatmap ===
fig, ax = plt.subplots(figsize=(8, 6))
np.random.seed(42)
tokens_x = ['The', 'cat', 'sat', 'on', 'the', 'mat', '.']
tokens_y = ['The', 'cat', 'sat', 'on', 'the', 'mat', '.']
# Generate sample attention weights (replace with actual weights)
attention = np.random.dirichlet(np.ones(len(tokens_x)), size=len(tokens_y))
sns.heatmap(attention, annot=True, fmt='.2f', cmap='Blues',
xticklabels=tokens_x, yticklabels=tokens_y,
ax=ax, square=True, linewidths=0.5,
cbar_kws={'label': 'Attention Weight'})
ax.set_xlabel('Key tokens')
ax.set_ylabel('Query tokens')
ax.set_title('Attention Weights')
plt.tight_layout()
plt.savefig('OUTPUT_NAME.png', dpi=300, bbox_inches='tight')
plt.savefig('OUTPUT_NAME.pdf', bbox_inches='tight')
print("Figure saved.")
''',
}
def main():
if "--list-types" in sys.argv:
print("Available figure types:")
for name in sorted(TEMPLATES.keys()):
print(f" {name}")
sys.exit(0)
parser = argparse.ArgumentParser(description="Generate figure script templates")
parser.add_argument("--type", required=True, choices=list(TEMPLATES.keys()),
help="Figure type")
parser.add_argument("--output", "-o", default="figure_script.py",
help="Output script file")
parser.add_argument("--name", default="figure", help="Output figure filename (without extension)")
parser.add_argument("--list-types", action="store_true")
args = parser.parse_args()
script = TEMPLATES[args.type].replace("OUTPUT_NAME", args.name)
with open(args.output, "w") as f:
f.write(script)
print(f"Template written to {args.output}", file=sys.stderr)
print(f"Run: python {args.output}", file=sys.stderr)
if __name__ == "__main__":
main()
Related skills
Forks & variants (2)
Figure Generation has 2 known copies in the catalog totaling 15 installs. They canonicalize to this original listing.
- lingzhi227 - 14 installs
- lingzhi227 - 1 installs
FAQ
What does figure-generation do?
Generate publication-quality scientific figures using matplotlib/seaborn with a three-phase pipeline (query expansion, code generation with execution, VLM visual feedback). Handles bar charts, line pl
When should I use figure-generation?
During idea research work for documentation.
Is figure-generation safe to install?
Review the Security Audits panel on this listing before production use.