Files
2026-07-13 12:35:23 +08:00

9.7 KiB
Raw Permalink Blame History

Python数据图表模块

本模块指导使用Python生成科研论文级别的数据图表。


一、环境要求

1.1 conda环境

默认环境名research

激活命令

conda activate research

必需库

pip install matplotlib seaborn numpy pandas scikit-learn

可选库

pip install plotly scipy statsmodels

1.2 环境配置

详见 modules/environment-setup.md 获取完整的环境配置指南。


二、图表规范

2.1 分辨率要求

用途 DPI 说明
期刊投稿 300-600 大多数期刊要求
顶刊投稿 450+ Nature/Science等
屏幕展示 150 PPT/网页
打印海报 300 A0/A1海报

本模块默认使用 450 DPI

2.2 输出格式

每张图同时输出两种格式:

  • PNG:位图,适合网页和PPT
  • SVG:矢量图,适合期刊投稿和后期编辑

2.3 图表尺寸

类型 宽度(英寸) 适用场景
单栏图 3.5 期刊单栏
双栏图 7.0 期刊双栏/全宽
PPT图 10.0 演示文稿

三、顶刊配色方案

3.1 Nature/Science 风格

NATURE_COLORS = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D', '#95C623']
颜色 色值 用途
深蓝 #2E86AB 主色调
玫红 #A23B72 对比色
橙色 #F18F01 强调色
砖红 #C73E1D 警示色
黄绿 #95C623 辅助色

3.2 Cell 风格

CELL_COLORS = ['#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F', '#EDC948']

3.3 渐变色系

# 蓝色渐变(适合热力图)
BLUE_GRADIENT = ['#A8DADC', '#6DAEDB', '#457B9D', '#2C5F7C', '#1D3557']

# 红蓝对比(适合正负值)
DIVERGING_COLORS = {
    'cold': ['#2166AC', '#4393C3', '#92C5DE', '#D1E5F0'],
    'neutral': '#F7F7F7',
    'warm': ['#FDDBC7', '#F4A582', '#D6604D', '#B2182B'],
}

3.4 色盲友好配色

COLORBLIND_SAFE = ['#0077BB', '#33BBEE', '#009988', '#EE7733', '#CC3311', '#EE3377']

3.5 配色原则

  • 禁止使用matplotlib默认颜色
  • 禁止使用纯红、纯蓝、纯绿等基础色
  • 同一图中颜色数量控制在5种以内
  • 确保色盲友好(避免红绿直接对比)
  • 使用渐变色表示连续变量

四、代码模板

4.1 基础模板

"""
Figure X: [图表标题]
论文章节: [所属章节]
描述: [图表内容描述]
"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
from pathlib import Path

# ============================================================
# 中文字体配置(macOS系统)
# ============================================================
CHINESE_FONT = None
font_candidates = [
    '/System/Library/Fonts/STHeiti Light.ttc',
    '/System/Library/Fonts/Supplemental/Songti.ttc',
    '/Library/Fonts/Songti.ttc',
    '/System/Library/Fonts/PingFang.ttc',
]
for fp in font_candidates:
    if Path(fp).exists():
        CHINESE_FONT = fm.FontProperties(fname=fp)
        break

if CHINESE_FONT is None:
    plt.rcParams['font.sans-serif'] = ['Heiti TC', 'STHeiti', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False

# ============================================================
# 顶刊配色
# ============================================================
COLORS = ['#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F', '#EDC948']

# ============================================================
# 全局样式设置
# ============================================================
def setup_plot_style():
    """配置全局绑定样式"""
    plt.rcParams.update({
        'font.family': 'sans-serif',
        'font.size': 10,
        'axes.titlesize': 12,
        'axes.labelsize': 10,
        'xtick.labelsize': 9,
        'ytick.labelsize': 9,
        'legend.fontsize': 9,
        'lines.linewidth': 1.5,
        'lines.markersize': 6,
        'axes.linewidth': 1.0,
        'axes.spines.top': False,
        'axes.spines.right': False,
        'axes.grid': True,
        'grid.alpha': 0.3,
        'grid.linewidth': 0.5,
        'legend.frameon': False,
        'savefig.dpi': 450,
        'savefig.bbox': 'tight',
        'savefig.pad_inches': 0.1,
        'figure.facecolor': 'white',
        'axes.facecolor': 'white',
    })

# ============================================================
# 主绑定代码
# ============================================================
def main():
    setup_plot_style()
    
    # === 在此处编写具体绑定代码 ===
    fig, ax = plt.subplots(figsize=(7, 5))
    
    # 示例数据
    x = np.linspace(0, 10, 100)
    ax.plot(x, np.sin(x), color=COLORS[0], label='Model A')
    ax.plot(x, np.cos(x), color=COLORS[1], label='Model B')
    
    # 标签设置(中文使用FontProperties
    if CHINESE_FONT:
        ax.set_xlabel('时间 (s)', fontproperties=CHINESE_FONT)
        ax.set_ylabel('幅值', fontproperties=CHINESE_FONT)
        ax.set_title('模型对比', fontproperties=CHINESE_FONT)
        ax.legend(prop=CHINESE_FONT)
    else:
        ax.set_xlabel('Time (s)')
        ax.set_ylabel('Amplitude')
        ax.set_title('Model Comparison')
        ax.legend()
    
    # === 绑定代码结束 ===
    
    # 保存图片
    output_dir = Path(__file__).parent
    fig_name = Path(__file__).stem
    
    plt.savefig(output_dir / f'{fig_name}.png', dpi=450, format='png')
    plt.savefig(output_dir / f'{fig_name}.svg', format='svg')
    
    plt.show()
    print(f"图片已保存至: {output_dir}")

if __name__ == '__main__':
    main()

4.2 常用图表类型

折线图

fig, ax = plt.subplots(figsize=(7, 5))
for i, (label, data) in enumerate(datasets.items()):
    ax.plot(x, data, color=COLORS[i], label=label, linewidth=1.5, marker='o', markersize=4)
ax.set_xlabel('Epoch')
ax.set_ylabel('Accuracy (%)')
ax.legend()

柱状图

fig, ax = plt.subplots(figsize=(7, 5))
x_pos = np.arange(len(categories))
bars = ax.bar(x_pos, values, color=COLORS[:len(categories)], edgecolor='white', linewidth=0.5)
ax.set_xticks(x_pos)
ax.set_xticklabels(categories)
ax.set_ylabel('Performance')

分组柱状图

fig, ax = plt.subplots(figsize=(8, 5))
x = np.arange(len(categories))
width = 0.25

for i, (label, values) in enumerate(groups.items()):
    ax.bar(x + i * width, values, width, label=label, color=COLORS[i])

ax.set_xticks(x + width)
ax.set_xticklabels(categories)
ax.legend()

热力图

fig, ax = plt.subplots(figsize=(8, 6))
im = ax.imshow(matrix, cmap='RdBu_r', aspect='auto', vmin=-1, vmax=1)
plt.colorbar(im, ax=ax, label='Correlation')
ax.set_xticks(range(len(labels)))
ax.set_xticklabels(labels, rotation=45, ha='right')
ax.set_yticks(range(len(labels)))
ax.set_yticklabels(labels)

箱线图

fig, ax = plt.subplots(figsize=(7, 5))
bp = ax.boxplot(data_list, labels=labels, patch_artist=True)
for patch, color in zip(bp['boxes'], COLORS):
    patch.set_facecolor(color)
    patch.set_alpha(0.7)

散点图

fig, ax = plt.subplots(figsize=(7, 5))
scatter = ax.scatter(x, y, c=colors, s=sizes, alpha=0.6, cmap='viridis')
plt.colorbar(scatter, ax=ax, label='Value')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')

五、文件管理

5.1 目录结构

项目目录/
├── figures/
│   ├── chapter1_introduction/
│   │   ├── fig1_overview.py
│   │   ├── fig1_overview.png
│   │   └── fig1_overview.svg
│   ├── chapter2_method/
│   │   └── ...
│   ├── chapter3_results/
│   │   └── ...
│   └── chapter4_discussion/
│       └── ...

5.2 命名规范

  • 文件名格式:fig{序号}_{描述}.py
  • 示例:fig1_model_architecture.py, fig5_accuracy_comparison.py
  • 输出图片与代码同名,仅扩展名不同

六、执行流程

6.1 标准流程

  1. 确认conda环境已激活

    conda activate research
    
  2. 创建/编辑Python脚本

    • 使用上述模板
    • 修改数据和绑定代码
  3. 运行脚本

    python figures/chapter1/fig1_xxx.py
    
  4. 检查输出

    • 确认PNG和SVG都已生成
    • 检查图表质量
  5. 如有错误,修复后重新运行

6.2 缺失库处理

# 使用pip安装
pip install [package_name]

# 或使用conda安装
conda install [package_name]

七、质量检查清单

图表内容

  • 数据准确无误
  • 坐标轴标签完整(含单位)
  • 图例清晰可读
  • 标题简洁明了

视觉效果

  • 使用顶刊配色方案
  • 分辨率达到450 DPI
  • 字体大小适中(可读)
  • 无多余的网格线或边框

文件输出

  • PNG格式已生成
  • SVG格式已生成
  • 文件命名规范
  • 存放在正确目录

八、常见问题

Q1:中文显示为方块

解决方案

# 方法1:指定字体文件
from matplotlib.font_manager import FontProperties
font = FontProperties(fname='/System/Library/Fonts/STHeiti Light.ttc')
ax.set_xlabel('中文标签', fontproperties=font)

# 方法2:全局设置
plt.rcParams['font.sans-serif'] = ['SimHei', 'Heiti TC', 'STHeiti']
plt.rcParams['axes.unicode_minus'] = False

Q2:图片模糊

解决方案

plt.savefig('figure.png', dpi=450, bbox_inches='tight')

Q3:颜色不够用

解决方案

# 使用colormap生成更多颜色
import matplotlib.cm as cm
colors = cm.viridis(np.linspace(0, 1, n_colors))

Q4:图例遮挡数据

解决方案

ax.legend(loc='upper left', bbox_to_anchor=(1.02, 1))
plt.tight_layout()