Scientific Visualization
Create publication-ready figures that are clear, accurate, and accessible.
When to Use
- Creating plots or visualizations for manuscripts
- Preparing figures for journal submission
- Ensuring figures are colorblind-friendly and accessible
- Making multi-panel figures with consistent styling
- Exporting figures at correct resolution and format
- Creating figures in
manuscript/figures/figN/
- During the ANALYSIS or WRITING phases
Quick Start: Publication Figure
import matplotlib.pyplot as plt
import numpy as np
# Publication settings
plt.rcParams.update({
'font.family': 'sans-serif',
'font.sans-serif': ['Arial', 'Helvetica'],
'font.size': 8,
'axes.labelsize': 9,
'axes.titlesize': 10,
'xtick.labelsize': 7,
'ytick.labelsize': 7,
'legend.fontsize': 7,
'figure.dpi': 300,
'savefig.dpi': 300,
'savefig.bbox': 'tight',
})
# Create figure (single column = 3.5 inches / 89mm)
fig, ax = plt.subplots(figsize=(3.5, 2.5))
# Plot with colorblind-safe colors
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), color='#0072B2', label='sin(x)')
ax.plot(x, np.cos(x), color='#D55E00', label='cos(x)')
# Proper labeling with units
ax.set_xlabel('Time (s)')
ax.set_ylabel('Amplitude (mV)')
ax.legend(frameon=False)
# Clean style
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Save
fig.savefig('manuscript/figures/fig1/figure1.pdf')
fig.savefig('manuscript/figures/fig1/figure1.png', dpi=300)
plt.close()
Colorblind-Safe Palettes
Okabe-Ito Palette (Recommended)
# Best for categorical data - distinguishable by all color vision types
OKABE_ITO = [
'#E69F00', # Orange
'#56B4E9', # Sky Blue
'#009E73', # Bluish Green
'#F0E442', # Yellow
'#0072B2', # Blue
'#D55E00', # Vermillion
'#CC79A7', # Reddish Purple
'#000000', # Black
]
plt.rcParams['axes.prop_cycle'] = plt.cycler(color=OKABE_ITO)
For Continuous Data
# Use perceptually uniform colormaps
cmap = 'viridis' # Default, good for most cases
cmap = 'plasma' # High contrast
cmap = 'cividis' # Colorblind-safe diverging
# AVOID: 'jet', 'rainbow', 'hsv' - these are NOT colorblind-safe
For Diverging Data
# Colorblind-safe diverging colormaps
cmap = 'RdBu_r' # Red-Blue (reversed so blue = low)
cmap = 'PuOr' # Purple-Orange
cmap = 'BrBG' # Brown-Blue-Green
# Always center diverging maps at meaningful zero
sns.heatmap(data, cmap='RdBu_r', center=0)
Journal Figure Sizes
Common Widths (in inches)
| Journal |
Single Column |
Double Column |
| Nature |
3.5" (89mm) |
7.2" (183mm) |
| Science |
2.2" (55mm) |
6.9" (175mm) |
| Cell |
3.3" (85mm) |
7.0" (178mm) |
| PLOS |
5.2" |
7.5" |
| Default |
3.5" |
7.0" |
Resolution Requirements
| Content Type |
Minimum DPI |
| Line art (graphs) |
600-1200 (or vector) |
| Photographs |
300-600 |
| Combination |
600 |
File Formats
| Format |
Use For |
Notes |
| PDF |
Primary |
Vector, preserves quality |
| EPS |
Journals |
Vector, legacy support |
| TIFF |
Images |
Lossless raster |
| PNG |
Web/screen |
Lossless, smaller than TIFF |
| JPEG |
NEVER |
Lossy compression artifacts |
Multi-Panel Figures
Using GridSpec
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from string import ascii_uppercase
# Create figure with custom layout
fig = plt.figure(figsize=(7, 5))
gs = GridSpec(2, 3, figure=fig, hspace=0.4, wspace=0.4)
# Create panels
ax_a = fig.add_subplot(gs[0, 0]) # Top left
ax_b = fig.add_subplot(gs[0, 1:]) # Top right (spans 2 columns)
ax_c = fig.add_subplot(gs[1, 0]) # Bottom left
ax_d = fig.add_subplot(gs[1, 1]) # Bottom middle
ax_e = fig.add_subplot(gs[1, 2]) # Bottom right
# Add panel labels
axes = [ax_a, ax_b, ax_c, ax_d, ax_e]
for i, ax in enumerate(axes):
ax.text(-0.15, 1.05, ascii_uppercase[i], transform=ax.transAxes,
fontsize=12, fontweight='bold', va='top')
# Example: clean up each axis
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.savefig('manuscript/figures/fig1/figure1.pdf')
Using Subplots
fig, axes = plt.subplots(2, 2, figsize=(7, 6))
axes = axes.flatten()
for i, ax in enumerate(axes):
ax.text(-0.1, 1.05, ascii_uppercase[i], transform=ax.transAxes,
fontsize=12, fontweight='bold', va='top')
plt.tight_layout()
Common Plot Types
Bar Plot with Error Bars
import matplotlib.pyplot as plt
import numpy as np
groups = ['Control', 'Treatment A', 'Treatment B']
means = [10.2, 15.8, 18.3]
sems = [1.2, 1.5, 1.8] # Standard error of mean
n = [20, 20, 20]
fig, ax = plt.subplots(figsize=(3.5, 3))
bars = ax.bar(groups, means, yerr=sems, capsize=4,
color=['#0072B2', '#E69F00', '#D55E00'],
edgecolor='black', linewidth=0.5)
ax.set_ylabel('Response (AU)')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Add individual data points (transparency)
for i, (group, n_i) in enumerate(zip(groups, n)):
x_jitter = np.random.normal(i, 0.05, n_i)
y_data = np.random.normal(means[i], sems[i]*np.sqrt(n_i), n_i)
ax.scatter(x_jitter, y_data, alpha=0.4, s=15, c='black')
plt.tight_layout()
Line Plot with Confidence Bands
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 10, 50)
y = np.sin(x) + np.random.normal(0, 0.2, 50)
y_smooth = np.sin(x)
ci = 0.3 # Confidence interval width
fig, ax = plt.subplots(figsize=(4, 3))
# Confidence band
ax.fill_between(x, y_smooth - ci, y_smooth + ci, alpha=0.3, color='#0072B2')
# Line
ax.plot(x, y_smooth, color='#0072B2', linewidth=2)
# Data points
ax.scatter(x, y, s=20, alpha=0.5, color='#0072B2')
ax.set_xlabel('Time (s)')
ax.set_ylabel('Signal (AU)')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
Box Plot with Significance Markers
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots(figsize=(4, 4))
# Box plot
sns.boxplot(data=df, x='group', y='value', palette='colorblind', ax=ax)
# Add individual points
sns.stripplot(data=df, x='group', y='value', color='black',
alpha=0.3, size=4, ax=ax)
# Add significance bar
y_max = df['value'].max()
ax.plot([0, 1], [y_max*1.1, y_max*1.1], 'k-', linewidth=1)
ax.text(0.5, y_max*1.12, '***', ha='center', fontsize=10)
ax.set_ylabel('Response (AU)')
sns.despine()
Heatmap with Proper Colorbar
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
# Correlation matrix example
fig, ax = plt.subplots(figsize=(5, 4))
# Mask upper triangle
mask = np.triu(np.ones_like(corr_matrix, dtype=bool))
sns.heatmap(corr_matrix, mask=mask, annot=True, fmt='.2f',
cmap='RdBu_r', center=0, square=True,
linewidths=0.5, cbar_kws={'shrink': 0.8},
vmin=-1, vmax=1, ax=ax)
ax.set_title('Correlation Matrix')
plt.tight_layout()
Seaborn for Statistical Plots
import seaborn as sns
# Apply publication style
sns.set_theme(style='ticks', context='paper', font_scale=1.1)
sns.set_palette('colorblind')
# Violin plot with split
fig, ax = plt.subplots(figsize=(4, 3))
sns.violinplot(data=df, x='timepoint', y='expression',
hue='treatment', split=True, inner='quartile', ax=ax)
ax.set_ylabel('Gene Expression (AU)')
sns.despine()
# Regression plot with CI
fig, ax = plt.subplots(figsize=(4, 3))
sns.regplot(data=df, x='predictor', y='outcome',
ci=95, scatter_kws={'alpha': 0.5}, ax=ax)
sns.despine()
Figure Export Workflow
For RA Projects
def save_figure(fig, fig_num, name):
"""Save figure in multiple formats following RA conventions."""
import os
# Create figure directory
fig_dir = f'manuscript/figures/fig{fig_num}'
os.makedirs(fig_dir, exist_ok=True)
# Save in multiple formats
fig.savefig(f'{fig_dir}/{name}.pdf', format='pdf', bbox_inches='tight')
fig.savefig(f'{fig_dir}/{name}.png', format='png', dpi=300, bbox_inches='tight')
fig.savefig(f'{fig_dir}/{name}.tiff', format='tiff', dpi=300, bbox_inches='tight')
print(f"Saved: {fig_dir}/{name}.{{pdf,png,tiff}}")
# Usage
save_figure(fig, 1, 'treatment_comparison')
Caption Template
Create manuscript/figures/fig1/caption.md:
**Figure 1. Treatment comparison across experimental groups.**
(A) Response levels in control (n=20), Treatment A (n=20), and Treatment B (n=20)
groups. Data shown as mean ± SEM with individual data points. ***p < 0.001,
one-way ANOVA with Tukey's post-hoc test.
(B) Time course of response following treatment. Shaded regions indicate 95%
confidence intervals. Treatment A (orange) shows significantly faster response
than control (blue), p < 0.01.
Accessibility Checklist
Integration with RA Workflow
- Create figure directory:
manuscript/figures/figN/
- Save figure files:
figure.pdf, figure.png
- Create caption:
caption.md
- Reference in
manuscript/results.md
- Log activity in
.research/logs/activity.md