English

制作适用于 LaTeX 的专业 Matplotlib 图像

🔠 字体

字体样式

为了确保 Matplotlib 图像中的字体与 LaTeX 正文中的字体完全一致,最佳做法是使用 LaTeX 进行字体渲染。这可以 100% 保证字体风格的一致性

安装 TeX Live

请在系统中安装 TeX Live:

  • macOS:brew install texlive
  • Debian / Ubuntu:apt install texlive-full
  • Windows:请参考 官方指南

安装完成后,请确保 pdflatex 可执行文件已正确加入到 PATH 中。

启用 LaTeX 字体渲染

import matplotlib.pyplot as plt

plt.rcParams.update({
    "text.usetex": True,
    "font.family": "Computer Modern",
})

字体大小

使用与 LaTeX 正文一致的字体大小,是获得专业外观的关键。虽然这一点在概念上非常简单,但在实际操作中,许多人仍然会在图例、刻度标签、图标题等元素的字体大小调整上遇到困难。

关键在于:字体大小是相对于图像尺寸而言的。 如果图像本身设置得过大,即使使用较大的字体参数,当图像插入到文档中时,文字仍然可能显得很小。

因此,字体大小控制中最重要、也是第一步,是正确设置图像尺寸。 其基本原则非常简单:图像的宽度应当与其在文档中的最终显示宽度完全一致。

如下图所示,对于 IEEE 双栏格式中的单栏图像,其列宽大约为 3.5 英寸。 只需将图像宽度设置为 3.5 英寸,字体大小就会自然地与 LaTeX 正文保持一致,而无需额外微调。

IEEE 双栏格式中,单栏列宽约为 3.5 英寸。

  1. 将图像宽度设置为与文档中显示宽度一致。在 IEEE 风格的双栏排版中,单栏宽度通常为 3.5 英寸。因此,对于单栏图像,只需将图像宽度设置为 3.5 英寸:
fig = plt.figure(figsize=(3.5, 3.5))
  1. 将字体大小设置为默认值,在 IEEE 模板中,默认字体为10pt,因此只需要将字体大小设置为10
import matplotlib as mpl
mpl.rcParams.update({
    "font.size": 10,
    "axes.labelsize": 10,
    "axes.titlesize": 10,
    "figure.titlesize": 10,
    "legend.fontsize": 9,
    "xtick.labelsize": 9,
    "ytick.labelsize": 9,
})

就这么简单——图像中的文字现在将与 LaTeX 正文中的字体保持一致。

📊 Matplotlib Legend 的精细控制

Legend 是 Matplotlib 坐标轴中的一个重要组成部分,用于标识和区分图中的不同元素。

Legend Location: loc

使用 legend(loc=) 指定图例的位置。 该参数既可以是精确坐标,也可以是字符串形式的位置描述,例如 For example: ax.legend(loc=(0, 0.5)) or ax.legend("upper left").

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(i/3, i/3))
plt.tight_layout()

Legend at different locations.

字体大小:fontsize

使用 legend(fontsize=) 指定图例字体大小。

fig, axes = plt.subplots(1, 3, figsize=(8, 3))

for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), fontsize=8+i*3)
plt.tight_layout()

Legend with various font sizes.

列数:ncol

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), ncol=i+1)
plt.tight_layout()

Legends of different columns.

行间距:labelspacing

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), ncol=2, labelspacing=2*i)
plt.tight_layout()

Adjust the spacing between columns.

列间距:columnspacing

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), ncol=2, columnspacing=2*i)
plt.tight_layout()

Adjust the spacing between columns.

Handle 长度: handlelength

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), ncol=2, handlelength=i+1)
plt.tight_layout()

Adjust handle length.

Handle 与文本之间的间距:handletextpad

fig, axes = plt.subplots(1, 3, figsize=(8, 3))
for i, ax in enumerate(axes):
    ax.set_ylim(-2, 1.1)
    for y in ys:
        axes[i].plot(x, y)
    axes[i].legend([f"i={i}" for i in range(5)], loc=(0, 0), ncol=2, handletextpad=i)
plt.tight_layout()

Space between handle and text.