| name | scientific-publication |
| description | Best practices for iterative refinement of publication-quality scientific figures. Covers systematic improvement workflows, layout optimization, and ensuring all figure elements are publication-ready. |
| version | 1.0.0 |
| context | fork |
| allowed-tools | Read, Grep, Glob, Bash |
Scientific Publication Figure Refinement
Expert guidance for systematically improving scientific figures through iterative refinement based on user feedback and publication requirements.
Supporting files in this directory:
When to Use This Skill
- Improving figures based on reviewer or collaborator feedback
- Optimizing figure clarity and readability
- Ensuring all figure elements fit within bounds
- Deciding between layout alternatives (horizontal vs vertical panels)
- Preparing figures for high-impact publications
Iterative Figure Refinement Workflow
Standard Refinement Sequence
When improving a publication figure, follow this systematic approach:
1. Identify the Core Issue
Examples:
- "Violin plots look distorted on log scale"
- "P-values are cut off at the top"
- "Too much visual clutter, hard to see the data"
- "Text overlaps with data points"
2. Fix the Visualization Type/Method
ax.violinplot(data)
ax.set_yscale('log')
ax.boxplot(data)
ax.set_yscale('log')
3. Improve Visual Clarity
Systematically adjust element sizes:
ax.scatter(..., s=25, alpha=0.5)
ax.plot(..., linewidth=1.5)
ax.text(..., fontsize=8)
ax.errorbar(..., capsize=5)
4. Test Layout Alternatives
fig, axes = plt.subplots(1, 2, figsize=(16, 7))
fig, axes = plt.subplots(2, 1, figsize=(10, 14))
5. Optimize Element Positioning
Ensure all annotations fit within plot bounds:
y_max = max([d.max() for d in data_list])
y_min = min([d.min() for d in data_list])
y_pos = y_max * 0.92
ax.set_ylim(y_min * 0.95 if y_min > 0 else y_min - 5,
y_max * 1.05)
Checklist for Publication Figures
Use this checklist before finalizing figures:
Common Refinement Patterns
Pattern 1: Decluttering Dense Plots
Problem: Too many visual elements competing for attention
Solution sequence:
- Reduce point size (60 -> 25)
- Thin line widths (2.5 -> 1.5)
- Increase transparency (alpha=0.8 -> 0.5)
- Reduce font sizes (10 -> 8)
- Remove grid or make it lighter (alpha=0.3)
Before/After test: Generate both versions, compare
Pattern 2: Fixing Overflow Issues
Problem: Annotations, legends, or labels cut off
Solutions:
y_pos = y_max * 0.92
plt.savefig('figure.png', dpi=300, bbox_inches='tight')
ax.set_ylim(min_val * 0.95, max_val * 1.05)
ax.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
ax.text(..., fontsize=8)
Pattern 3: Multi-Panel Layout Optimization
Try both orientations:
fig, axes = plt.subplots(1, 2, figsize=(16, 7))
plt.savefig('fig_horizontal.png', dpi=300, bbox_inches='tight')
fig, axes = plt.subplots(2, 1, figsize=(10, 14))
plt.savefig('fig_vertical.png', dpi=300, bbox_inches='tight')
Decision criteria:
- Horizontal: Better for direct comparison between panels
- Vertical: Better when each panel needs more space
- User context: Journal column width, presentation slides, etc.
Pattern 4: Iterative Statistical Annotation
Common issue: P-values positioned outside plot or overlapping with data
Solution:
all_data = [data_dual, data_prialt]
y_max = max([d.max() for d in all_data if len(d) > 0])
for i, (x_pos, comparison) in enumerate(comparisons):
stat, pval = stats.mannwhitneyu(...)
y_annotation = y_max * 0.92
if pval < 0.001:
text = 'p < 0.001***'
elif pval < 0.01:
text = 'p < 0.01**'
elif pval < 0.05:
text = 'p < 0.05*'
else:
text = f'p = {pval:.3f} ns'
ax.text(x_pos, y_annotation, text, ha='center', fontsize=9)
ax.set_ylim(0, y_max * 1.05)
Refinement Workflow Example
Real case: VGP Figure 5 improvement sequence
-
Initial version: 4 categories, violin plots on log scale
- Issue: Violin distortion, too complex
-
V1 refinement: Remove violin plots, keep boxplots
-
V2 refinement: Simplify to 3 categories
-
V3 refinement: Reduce point sizes (60->25), thin lines (2.5->1.5)
-
V4 refinement: Test vertical vs horizontal layout
- Horizontal clearer for this case
-
V5 refinement: Fix p-value positioning (105%->92% of y_max)
-
Final: Smaller text in statistics box (10->8)
Total iterations: 7 versions over refinement process
Result: Clear, accurate, publication-quality figure
Best Practices
1. Version Your Refinements
Keep working versions during major changes:
scripts/
plot_figure.py
plot_figure_v2.py
plot_figure_final.py
2. Generate Alternatives in Parallel
When testing layout options:
layouts = [
((1, 2), (16, 7), 'horizontal'),
((2, 1), (10, 14), 'vertical')
]
for (nrows, ncols), figsize, name in layouts:
fig, axes = plt.subplots(nrows, ncols, figsize=figsize)
plt.savefig(f'figure_{name}.png', dpi=300, bbox_inches='tight')
3. Document Each Refinement
"""
Figure 5 - Terminal Telomere Presence
Version history:
- v1: Initial 4-category version with violin plots
- v2: Removed violin plots (distortion on log scale)
- v3: Simplified to 3 categories (terminal only)
- v4: Reduced point/line sizes for clarity
- v5: Fixed p-value positioning
- final: Publication ready
Changes from v4 -> v5:
- P-value y-position: 1.05 * y_max -> 0.92 * y_max
- Added explicit y-axis limits: (y_min*0.95, y_max*1.05)
- Ensures all annotations visible within plot bounds
"""
4. Get Feedback at Key Milestones
Don't over-iterate without input:
- After fixing major issues (wrong plot type): Show user
- After layout changes (horizontal vs vertical): Show user
- After final polish: Show user
5. Maintain Consistency Across Figure Set
If refining one figure, check if same improvements apply to others:
Summary
Systematic refinement workflow:
- Identify issue -> 2. Fix visualization -> 3. Improve clarity -> 4. Test layouts -> 5. Optimize positioning
Key principles:
- Iterate based on user feedback
- Test alternatives (show options)
- Document changes
- Apply lessons across figure set
- Meet publication standards
Common adjustments:
- Point sizes: 60 -> 25
- Line widths: 2.5 -> 1.5
- Font sizes: 10 -> 8
- Annotation positions: 105% -> 92% of max
- Always set explicit axis limits
For additional guidance, see the supporting files: