出版级科学可视化
概述
科学可视化(Scientific Visualization)将数据转化为清晰、准确的图形用于出版。本技能涵盖:多面板布局(Multi-panel Layouts)、误差线(Error Bars)、显著性标记、色盲安全调色板(Colorblind-safe Palettes)、期刊格式化要求。协调 Matplotlib、Seaborn 和 Plotly 以满足出版样式需求。
适用场景
- 为科学手稿创建图表
- 准备期刊投稿图形(Nature、Science、Cell、PLOS 等)
- 确保图形色盲友好且可访问
- 创建风格一致的多面板图形
- 按正确的分辨率和格式导出图形
- 遵循特定出版指南
快速开始
基础出版级图形
import matplotlib.pyplot as plt
import numpy as np
# 创建适当尺寸的图形(单栏 = 3.5 英寸)
fig, ax = plt.subplots(figsize=(3.5, 2.5))
# 绑图
x = np.linspace(0, 10, 100)
ax.plot(x, np.sin(x), label='sin(x)')
ax.plot(x, np.cos(x), label='cos(x)')
# 带单位的标签
ax.set_xlabel('Time (seconds)')
ax.set_ylabel('Amplitude (mV)')
ax.legend(frameon=False)
# 移除多余边框
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# 保存为出版格式
plt.savefig('figure1.pdf', bbox_inches='tight')
plt.savefig('figure1.png', dpi=300, bbox_inches='tight')
使用预配置样式
import matplotlib.pyplot as plt
# 使用期刊样式文件
plt.style.use('nature.mplstyle')
# 创建图形 — 自动匹配 Nature 规格
fig, ax = plt.subplots()
# ... 你的绘图代码 ...
与 Seaborn 结合
import seaborn as sns
import matplotlib.pyplot as plt
# 应用出版样式
sns.set_theme(style='ticks', context='paper', font_scale=1.1)
sns.set_palette('colorblind')
# 创建统计比较图
fig, ax = plt.subplots(figsize=(3.5, 3))
sns.boxplot(data=df, x='treatment', y='response',
order=['Control', 'Low', 'High'], palette='Set2', ax=ax)
sns.stripplot(data=df, x='treatment', y='response',
order=['Control', 'Low', 'High'],
color='black', alpha=0.3, size=3, ax=ax)
ax.set_ylabel('Response (μM)')
sns.despine()
核心原则与最佳实践
1. 分辨率与文件格式
| 图像类型 | 分辨率要求 | 推荐格式 |
|---|---|---|
| 光栅图像(Raster):照片、显微镜 | 300-600 DPI | TIFF、PNG |
| 线条图(Line Art):图表、绘图 | 600-1200 DPI 或矢量 | PDF、EPS、SVG |
| 组合图(Combination) | 600 DPI |
重要:科学数据图表永远不要使用 JPEG 格式(会产生压缩伪影)
2. 色盲安全的颜色选择
推荐:Okabe-Ito 调色板(可被所有类型的色盲辨识):
okabe_ito = ['#E69F00', '#56B4E9', '#009E73', '#F0E442',
'#0072B2', '#D55E00', '#CC79A7', '#000000']
plt.rcParams['axes.prop_cycle'] = plt.cycler(color=okabe_ito)
| 颜色名称 | 十六进制 | 用途 |
|---|---|---|
| 橙色(Orange) | #E69F00 |
分类 1 |
| 天蓝(Sky Blue) | #56B4E9 |
分类 2 |
| 蓝绿(Bluish Green) | #009E73 |
分类 3 |
| 黄色(Yellow) | #F0E442 |
分类 4 |
| 蓝色(Blue) | #0072B2 |
分类 5 |
| 朱红(Vermillion) | #D55E00 |
分类 6 |
| 紫红(Reddish Purple) | #CC79A7 |
分类 7 |
热力图/连续数据:
- 使用感知均匀色彩映射:
viridis、plasma、cividis - 避免红绿发散映射(使用
PuOr、RdBu、BrBG替代) - 永远不要使用
jet或rainbow
始终在灰度模式下测试图形,确保可解读性
3. 排版与文字
字体指南:
- 无衬线字体(Sans-serif):Arial、Helvetica、Calibri
- 最终印刷尺寸下的最小字号:
- 坐标轴标签(Axis Labels):7-9 pt
- 刻度标签(Tick Labels):6-8 pt
- 面板标签(Panel Labels):8-12 pt(加粗)
- 使用句式大写:
"Time (hours)"而非"TIME (HOURS)" - 始终在括号中包含单位
import matplotlib as mpl
mpl.rcParams['font.family'] = 'sans-serif'
mpl.rcParams['font.sans-serif'] = ['Arial', 'Helvetica']
mpl.rcParams['font.size'] = 8
mpl.rcParams['axes.labelsize'] = 9
mpl.rcParams['xtick.labelsize'] = 7
mpl.rcParams['ytick.labelsize'] = 7
4. 期刊尺寸要求
| 期刊 | 单栏宽度 | 双栏宽度 | 最大高度 |
|---|---|---|---|
| Nature | 89 mm (3.5 in) | 183 mm (7.2 in) | 247 mm (9.7 in) |
| Science | 55 mm (2.17 in) | 175 mm (6.89 in) | 233 mm (9.17 in) |
| Cell | 85 mm (3.35 in) | 178 mm (7.01 in) | 230 mm (9.06 in) |
Nature 特别要求:
- 面板标签:a、b、c(小写、加粗),位于左上角
- 显微镜图像需要比例尺
- 统计:标记显著性,在图例中定义符号
Science 特别要求:
- 面板标签:(A)、(B)、(C) 带括号
- 图中文本最少(细节放在图注中)
- 误差线必须标注,在图注中定义
Cell 特别要求:
- 面板标签:A、B、C(大写、加粗)
- 字体 6-8 pt(最终尺寸)
5. 多面板图形
最佳实践:
- 用加粗字母标注面板:A、B、C(大多数期刊用大写,Nature 用小写)
- 保持所有面板风格一致
- 尽量沿边对齐面板
- 面板间留足空白
from string import ascii_uppercase
fig = plt.figure(figsize=(7, 4))
gs = fig.add_gridspec(2, 2, hspace=0.4, wspace=0.4)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[0, 1])
ax3 = fig.add_subplot(gs[1, 0])
ax4 = fig.add_subplot(gs[1, 1])
# 添加面板标签
for i, ax in enumerate([ax1, ax2, ax3, ax4]):
ax.text(-0.15, 1.05, ascii_uppercase[i], transform=ax.transAxes,
fontsize=10, fontweight='bold', va='top')
使用 Seaborn 创建多面板
FacetGrid 自动分面:
g = sns.relplot(data=df, x='dose', y='response',
hue='treatment', col='cell_line', row='timepoint',
kind='line', height=2.5, aspect=1.2,
errorbar=('ci', 95), markers=True)
g.set_axis_labels('Dose (μM)', 'Response (AU)')
g.set_titles('{row_name} | {col_name}')
sns.despine()
Seaborn + Matplotlib 子图:
fig, axes = plt.subplots(2, 2, figsize=(7, 6))
sns.regplot(data=df, x='predictor', y='response', ax=axes[0, 0])
axes[0, 0].text(-0.15, 1.05, 'A', transform=axes[0, 0].transAxes,
fontsize=10, fontweight='bold')
sns.violinplot(data=df, x='group', y='value', ax=axes[0, 1])
axes[0, 1].text(-0.15, 1.05, 'B', transform=axes[0, 1].transAxes,
fontsize=10, fontweight='bold')
sns.heatmap(correlation_data, cmap='viridis', ax=axes[1, 0])
axes[1, 0].text(-0.15, 1.05, 'C', transform=axes[1, 0].transAxes,
fontsize=10, fontweight='bold')
sns.lineplot(data=timeseries, x='time', y='signal',
hue='condition', ax=axes[1, 1])
axes[1, 1].text(-0.15, 1.05, 'D', transform=axes[1, 1].transAxes,
fontsize=10, fontweight='bold')
plt.tight_layout()
sns.despine()
统计严谨性
始终包含:
- 误差线(Error Bars)— SD、SEM 或 CI,在图注中说明使用了哪种
- 样本量 (n) — 在图形或图注中标注
- 统计显著性标记 — *、**、***
- 尽可能显示单个数据点(不仅是汇总统计量)
# 显示单个数据点 + 汇总统计
ax.scatter(x_jittered, individual_points, alpha=0.4, s=8)
ax.errorbar(x, means, yerr=sems, fmt='o', capsize=3)
# 标记显著性
ax.text(1.5, max_y * 1.1, '***', ha='center', fontsize=8)
Seaborn 自动计算不确定性:
# 折线图:默认显示均值 ± 95% 置信区间
sns.lineplot(data=df, x='time', y='value', hue='treatment',
errorbar=('ci', 95))
# 柱状图:显示自举置信区间
sns.barplot(data=df, x='treatment', y='response',
errorbar=('ci', 95), capsize=0.1)
使用 Plotly 的出版级导出
fig.update_layout(
font=dict(family='Arial, sans-serif', size=10),
plot_bgcolor='white',
)
fig.write_image('figure.png', scale=3) # scale=3 约等于 300 DPI
工作流总结
- 规划 — 确定目标期刊、图形类型和内容
- 配置 — 应用对应期刊的样式
- 创建 — 构建图形,包含正确的标签、颜色、统计信息
- 验证 — 检查尺寸、字体、颜色、可访问性
- 导出 — 保存为要求的格式
- 审查 — 在手稿上下文中查看最终尺寸效果
投稿前检查清单
- 分辨率满足期刊要求(300+ DPI)
- 文件格式正确(图表用矢量格式,图像用 TIFF)
- 图形尺寸符合期刊规格
- 所有文字在最终尺寸下可读(6 pt 以上)
- 颜色色盲友好
- 灰度模式下图形可解读
- 所有坐标轴标注单位
- 误差线存在,且在图注中定义
- 面板标签存在且一致
- 无图表垃圾(Chart Junk)或 3D 效果
- 字体在所有图形中一致
- 统计显著性清晰标记
- 图例清晰完整
常见陷阱
| 陷阱 | 说明 |
|---|---|
| 字号过小 | 最终印刷尺寸下文字不可读 |
| 使用 JPEG | 图表/绘图永远不要用 JPEG(产生伪影) |
| 红绿配色 | 约 8% 男性无法区分红绿色 |
| 分辨率过低 | 出版物中图形像素化 |
| 缺少单位 | 坐标轴始终标注单位 |
| 3D 效果 | 扭曲感知,完全避免 |
| 截断坐标轴 | 柱状图从零开始(除非有科学依据) |
| 风格不一致 | 同一手稿中不同图形使用不同字体/颜色 |
| 缺少误差线 | 始终展示不确定性 |