LaTeX多图并排排版实战:subcaption宏包与minipage环境详解
2026/8/22 20:26:06 网站建设 项目流程

1. 项目概述:为什么LaTeX图片排版值得深究?

写论文、做报告,尤其是理工科的朋友,对LaTeX一定不陌生。它强大的公式排版能力让人爱不释手,但一到图片排版,很多人就开始头疼了。特别是当我们需要将多张图片并排放置,并且每张图下面还要配上独立的说明文字(caption)时,问题就来了:直接用\includegraphics排出来的图总是乱跑,说明文字对不上号,或者几张图挤在一起根本没法看。这看似是个小问题,却直接影响文档的美观度和专业性。

我自己在撰写学术论文和技术报告时,就无数次掉进这个“坑”里。最初以为用几个minipage环境套一下就能解决,结果发现编号错乱、浮动体乱跑,调试起来比写正文还费时间。后来经过大量实践和查阅资料,才摸索出一套稳定、灵活且符合出版规范的解决方案。这篇文章,我就来彻底拆解LaTeX中并排多张图片并添加独立说明的几种核心方法。无论你是正在被毕业论文图表折磨的学生,还是需要制作精美技术文档的工程师,这套方法都能让你告别折腾,高效产出。

2. 核心思路与方案选型:minipagesubfigure还是subcaption

面对多图并排的需求,LaTeX社区提供了多种工具,但各有优劣和适用场景。选择不当,后期调整会非常痛苦。我们首先需要理解LaTeX处理图片的底层逻辑:图片通常被放在figure浮动环境中,LaTeX为了优化版面,会将这些浮动体移动到它认为合适的位置(比如页面顶部或底部),这就是“图跑飞了”的根源。我们的目标是在尊重浮动体机制的前提下,实现对多张图片的精确控制。

2.1 三种主流方案深度对比

在实际操作中,最常被提及的有三种方案:基础的minipage组合、经典的subfigure宏包和现代推荐的subcaption宏包。它们并非简单的替代关系,而是适用于不同需求和复杂度的场景。

方案核心宏包优点缺点最佳适用场景
minipage组合无需额外宏包(LaTeX内核支持)1. 零依赖,兼容性极佳。
2. 控制粒度最细,可精确调整每个“小盒子”的宽度、对齐等。
3. 不局限于图片,可排版任何内容。
1.无法生成子图编号(如(a)、(b))
2. 需要手动管理\caption\label,容易出错。
3. 浮动体行为需额外小心处理。
1. 快速原型或简单并列。
2. 需要并排非图片内容(如公式、表格)。
3. 对编号无要求的内部文档。
subfigure宏包\usepackage{subfigure}1. 提供标准的子图编号功能((a), (b), (c)...)。
2. 语法直观,\subfigure命令专为子图设计。
3. 社区历史久,很多老模板在用。
1.已过时,与较新的caption宏包可能冲突
2. 自定义样式(如编号格式)相对麻烦。
3. 未来维护性差,不推荐在新项目中使用。
维护或投稿至仍要求此宏包的特定老期刊模板。
subcaption宏包\usepackage{subcaption}1.现代标准方案,与caption宏包完美配合,样式控制强大。
2. 提供\subcaptionboxsubfigure环境两种灵活语法。
3. 支持交叉引用子图(如“见图1a”),引用主图则包含所有子图。
4. 文档完善,社区支持好。
1. 需要加载caption宏包以获得最佳效果,略有学习成本。
2. 对于极度简单的并列,稍显“重”。
绝大多数新项目、毕业论文、学术期刊投稿的首选。功能全面,未来兼容性好。

注意subfig宏包是另一个选择,功能与subcaption类似,但两者语法不兼容。目前subcaption因其与caption宏包的无缝集成而被更广泛地推荐。

2.2 为什么我强烈推荐subcaption方案?

从上面的对比可以看出,subcaption方案在功能、兼容性和未来性上取得了最佳平衡。它解决了minipage无法自动编号的核心痛点,又避免了subfigure的过时和潜在冲突。更重要的是,它赋予了我们对子图说明文字样式的强大控制力——你可以轻松地统一修改所有子图说明的字体、间距、编号格式,这对于需要严格遵守格式要求的学术出版至关重要。

因此,下文将重点详解基于minipage的底层原理(帮助你理解核心机制)和基于subcaption的现代最佳实践。掌握了这两者,你就能应对几乎所有多图排版场景。

3. 方案一:使用minipage环境进行底层控制

minipage环境就像一个可以放在页面任何位置的“迷你页面”。我们可以创建多个等宽的minipage,将图片和说明文字分别放入,从而实现并排。这是最基础、最灵活的方法,理解它有助于你理解LaTeX排版的核心思想。

3.1 基础实现步骤与代码解析

假设我们需要并排两张图,每张图占页面宽度的45%,中间留10%的空白作为间隔。

\documentclass{article} \usepackage{graphicx} % 必须引入,用于插入图片 \usepackage{blindtext} % 仅用于生成示例文本,你的实际文档不需要 \begin{document} \blindtext % 这是一些示例文本,用来展示浮动体位置 \begin{figure}[htbp] % htbp是浮动体位置参数,表示优先尝试此处(h),页顶(t),页底(b),独立页(p) \centering % 让整个figure环境内容居中 % 第一个minipage,宽度为0.45\textwidth (即文本宽度的45%) \begin{minipage}{0.45\textwidth} \centering % 让minipage内的内容居中 \includegraphics[width=\linewidth]{example-image-a} % \linewidth在此等于minipage的宽度 \caption{这是第一张图的说明。} % 这个\caption属于这个minipage \label{fig:minipage-a} % 为这张图设置标签,用于交叉引用 \end{minipage} \hfill % 一个弹性填充,将两个minipage推到两端,中间产生空白 % 第二个minipage \begin{minipage}{0.45\textwidth} \centering \includegraphics[width=\linewidth]{example-image-b} \caption{这是第二张图的说明。} \label{fig:minipage-b} \end{minipage} \caption{两张并排图片的总说明} % 这个\caption属于整个figure环境 \label{fig:minipage-total} \end{figure} \blindtext % 更多示例文本 \end{document}

关键点解析:

  1. \begin{minipage}{宽度}:创建一个指定宽度的迷你页面。宽度可以用绝对单位(如5cm),但更推荐使用相对单位\textwidth(当前文本行宽)的比例,这样在不同页面尺寸下更自适应。
  2. \includegraphics[width=\linewidth]{...}:这里的\linewidth是一个神奇的长度变量,在minipage内部,它自动等于minipage的宽度。这样设置可以确保图片完美填满为其分配的宽度,不会溢出。
  3. \hfill:这是一个水平方向的“弹簧”或“胶水”,它会尽可能地将左右两侧的内容推开。放在两个minipage之间,能产生自适应的间距,比写死一个\hspace{2cm}更优雅、更灵活。
  4. \caption的位置:注意,代码中有三个\caption。前两个位于各自的minipage内,为每张子图生成说明。最后一个位于figure环境的末尾,为整个“图1”生成一个总说明。在最终的文档中,你会看到“图1: 两张并排图片的总说明”,然后下面有两张并排的图,每张图下面分别有“(a) 这是第一张图的说明。”和“(b) 这是第二张图的说明。”吗?并不会!这就是minipage方案的核心缺陷。

3.2minipage方案的致命缺陷与变通

运行上面的代码,你会发现一个严重问题:子图下面并没有出现形如“(a)”、“(b)”的自动编号。两个minipage中的\caption命令生成了独立的“图1”和“图2”,这完全违背了我们的初衷。

minipage环境本身并不感知外部的figure浮动体编号。每个minipage里的\caption都会触发一次独立的图计数器递增。要解决这个问题,我们必须手动模拟子图编号,放弃使用\caption命令。

改进后的minipage方案(手动编号):

\begin{figure}[htbp] \centering \begin{minipage}{0.45\textwidth} \centering \includegraphics[width=\linewidth]{example-image-a} \textbf{(a)} % 手动添加子图编号 \\ % 换行 这是第一张图的说明。 \label{fig:manual-a} % \label仍然可以加,但引用时需注意 \end{minipage} \hfill \begin{minipage}{0.45\textwidth} \centering \includegraphics[width=\linewidth]{example-image-b} \textbf{(b)} \\ 这是第二张图的说明。 \label{fig:manual-b} \end{minipage} \caption{两张并排图片的总说明。左(a)为XXX,右(b)为YYY。} % 只有一个总caption \label{fig:manual-total} \end{figure}

这个方案能实现视觉上的并排和说明,但\label无法被正常用于交叉引用子图(如\ref{fig:manual-a}可能不会显示为“(a)”),并且所有格式都需要手动调整,非常繁琐。因此,minipage方案仅适用于对编号和引用没有严格要求,或者需要高度自定义非图片内容并排的场合。

4. 方案二:使用subcaption宏包(现代标准方案)

subcaption宏包的出现,完美解决了minipage的痛点。它提供了两种主要语法:\subcaptionbox命令和subfigure环境。我推荐使用subfigure环境,因为它结构更清晰,功能更完整。

4.1 环境准备与宏包加载

首先,你需要在文档导言区(\begin{document}之前)正确加载必要的宏包。

\documentclass{article} \usepackage{graphicx} % 插入图片 \usepackage{caption} % 增强caption样式控制,subcaption依赖它或与之协同工作 \usepackage{subcaption} % 核心宏包,提供子图功能 % 可选:使用caption宏包统一设置说明样式 \captionsetup[figure]{font=small, labelfont=bf} % 设置所有图注为小字体,标签加粗 \captionsetup[subfigure]{font=scriptsize, labelfont=rm} % 设置子图注为更小字体,标签为正体 \begin{document}

加载顺序很重要:建议先graphicx,再caption,最后subcaptioncaption宏包不是subcaption的强制依赖,但一起使用能获得最强的样式控制能力。

4.2 使用subfigure环境实现并排与编号

subfigure环境的使用逻辑非常直观:在一个大的figure浮动体内,创建多个subfigure环境,每个subfigure就是一个子图单元。

\begin{figure}[htbp] \centering % 第一个子图 \begin{subfigure}[b]{0.45\textwidth} % [b]表示子图内容底部对齐,宽度占45% \centering \includegraphics[width=\linewidth]{example-image-a} \caption{第一张子图的详细说明。} % 这里会自动生成如 (a) 的编号 \label{fig:sub-a} \end{subfigure} \hfill % 同样使用\hfill创造弹性间距 % 第二个子图 \begin{subfigure}[b]{0.45\textwidth} \centering \includegraphics[width=\linewidth]{example-image-b} \caption{第二张子图的详细说明。} \label{fig:sub-b} \end{subfigure} % 可以继续添加更多子图... \caption{这是一个包含两个子图的示例。左子图(a)展示了...,右子图(b)展示了...。} \label{fig:total} \end{figure}

代码详解与技巧:

  1. \begin{subfigure}[位置]{宽度}[位置]参数可以是t(顶部对齐)、b(底部对齐)、c(居中,默认)。当子图高度不一致时,使用[b]能确保所有图片的底部对齐,视觉效果更整齐。{宽度}定义了子图区域的宽度。
  2. 自动编号:每个subfigure环境内的\caption会自动获得一个子图编号,如“(a)”、“(b)”。这个编号格式可以通过\captionsetup[subfigure]{...}全局修改。
  3. 独立的\label:为每个子图设置独立的\label(如fig:sub-a),这是实现精准交叉引用的关键。
  4. \captionfigure环境末尾的\caption生成整个图的标题(如“图1”)和总说明。

编译后效果:你会得到编号为“图1”的浮动体。其下方并排两张图,图下方分别有“(a) 第一张子图的详细说明。”和“(b) 第二张子图的详细说明。”。文档中你可以用\ref{fig:total}引用整个图1,用\ref{fig:sub-a}\ref{fig:sub-b}分别引用子图(a)和(b)。

4.3 多行多列复杂排版

subcaption的强大之处在于可以轻松组合出复杂的布局。例如,实现一个2行×2列的图片矩阵:

\begin{figure}[htbp] \centering % 第一行 \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=0.9\linewidth]{example-image-a} % 图片稍小于区域宽度,更美观 \caption{特征提取结果A} \label{fig:matrix-a} \end{subfigure} \hfill \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=0.9\linewidth]{example-image-b} \caption{特征提取结果B} \label{fig:matrix-b} \end{subfigure} \\[4pt] % 换行并增加一点点行间距,比单纯\\更好 % 第二行 \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=0.9\linewidth]{example-image-c} \caption{模型输出C} \label{fig:matrix-c} \end{subfigure} \hfill \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=0.9\linewidth]{example-image-a} % 复用图片示例 \caption{对比分析D} \label{fig:matrix-d} \end{subfigure} \caption{一个2x2的图片矩阵示例,展示了不同阶段的处理结果。} \label{fig:matrix-total} \end{figure}

关键技巧:

  • \\[距离]:用于换行。[4pt]在换行后增加了4pt的垂直间距,让行与行之间不至于太拥挤。你可以根据需要调整这个值(如[6pt][1ex])。
  • 图片宽度控制:使用width=0.9\linewidth让图片宽度为子图区域宽度的90%,这样图片四周会留有一些空白,看起来不会太满,尤其是在图片有边框时效果更好。
  • 对齐一致性:确保同一行所有subfigure的宽度总和加上\hfill的数量,不超过\textwidth。通常0.48+0.48<1,留出的空间正好由\hfill填充为间距。

4.4 使用\subcaptionbox命令的简洁语法

对于简单的并排,subcaption还提供了更紧凑的\subcaptionbox命令。它把子图内容、标题和标签合成一行命令。

\begin{figure}[htbp] \centering \subcaptionbox{子图A说明\label{fig:box-a}}[0.45\textwidth] % 说明和标签在前 {\includegraphics[width=\linewidth]{example-image-a}} % 图片内容在后 \hfill \subcaptionbox{子图B说明\label{fig:box-b}}[0.45\textwidth] {\includegraphics[width=\linewidth]{example-image-b}} \caption{使用\texorpdfstring{\textbackslash subcaptionbox}{subcaptionbox}命令的示例。} \label{fig:box-total} \end{figure}

这种语法更简洁,但可读性稍差,尤其是当图片插入命令本身很复杂时。我个人更倾向于使用subfigure环境,因为结构清晰,便于后期添加额外内容或格式调整。

5. 高级技巧与深度定制

掌握了基本方法后,一些高级技巧能让你排版出的图片更加专业和美观。

5.1 统一设置图片宽度与自适应缩放

我们经常需要所有子图宽度一致。除了在每个\includegraphics中设置width,更好的方法是定义一个统一的比例系数。

% 在导言区或figure环境前定义 \newcommand{\figwidth}{0.9\linewidth} % 图片占子图区域宽度的90% \begin{subfigure}{0.45\textwidth} \centering \includegraphics[width=\figwidth]{example-image-a} % 使用自定义命令 \caption{...} \label{...} \end{subfigure}

这样做的好处是,如果你想调整所有图片的显示比例,只需修改\figwidth的定义一处即可。

对于高度不一致的图片,如果希望它们高度统一,可以使用height参数,但要注意这可能扭曲图片比例。更推荐的方法是保持宽高比,统一宽度,让高度自适应。

\includegraphics[width=\figwidth, height=5cm, keepaspectratio]{example-image} % 不推荐,可能留白或拉伸 \includegraphics[width=\figwidth]{example-image} % 推荐:统一宽度,高度自适应

5.2 自定义子图编号与说明样式

通过captionsubcaption宏包,你可以深度定制说明文字的样式。

\usepackage{caption} \usepackage{subcaption} % 设置主图(caption)样式:小号字体,标签加粗,与图片间距较小 \captionsetup[figure]{font=small, labelfont=bf, labelsep=period, skip=2pt} % 设置子图(subcaption)样式:更小字体,标签使用括号,居中对齐 \captionsetup[subfigure]{font=scriptsize, labelfont=rm, labelformat=brace, justification=centering} % 如果你想改变子图编号的格式,比如从(a),(b)变成(a.),(b.) \renewcommand{\thesubfigure}{(\alph{subfigure}).} % 在导言区添加
  • labelsep:标签(如“图1”)和说明文本之间的分隔符,period表示句点,space表示空格,none表示无分隔。
  • skip:说明文字与图片/上方内容的垂直间距。
  • labelformat:子图标签的格式,brace表示用括号包裹,simple则直接显示a,b。
  • justification:说明文字的对齐方式,centering居中,raggedright左对齐(适合长说明)。

5.3 处理超宽图片与\centering的奥秘

有时并排的图片总宽度会略微超出文本宽度,导致溢出到页边。除了检查宽度总和,确保0.48+0.48<1外,\centering的作用域是关键。

\begin{figure}[htbp] % \centering 在这里!影响整个figure环境 \centering \begin{subfigure}{0.49\textwidth} % \centering 在这里!影响这个subfigure内部 \centering ... \end{subfigure} \hfill ... \end{figure}

重要经验\centering的作用范围是当前分组(环境)。figure环境里的\centering确保所有子图整体居中。每个subfigure环境里的\centering确保该子图的内容在其0.49\textwidth的宽度内居中。两者缺一不可。

6. 实战问题排查与解决方案

即使知道了方法,实操中还是会遇到各种“坑”。下面是我总结的常见问题及解决方法。

6.1 常见编译错误与警告

  1. “Undefined control sequence. \begin{subfigure}”

    • 原因:没有加载subcaption宏包。
    • 解决:在导言区添加\usepackage{subcaption}
  2. “Package caption Error: `subcaption' outside float.”

    • 原因subfigure环境用在了figuretable浮动环境之外。
    • 解决:确保所有subfigure都嵌套在一个figure环境内部。
  3. “Label `fig:xx' multiply defined.”

    • 原因:在文档中重复使用了相同的\label{}标签名。
    • 解决:为每个需要引用的图、子图、公式、章节等赋予唯一且具有描述性的标签名。建议使用前缀,如fig:tab:eq:sec:
  4. 图片引用显示为“??”

    • 原因:LaTeX需要编译两次来正确解析交叉引用。第一次编译生成.aux文件记录标签位置,第二次编译才读取这些信息。
    • 解决连续编译两次。在编辑器中,直接点击“编译”按钮两次,或者使用pdflatex -> bibtex -> pdflatex -> pdflatex的标准工作流(如果涉及参考文献)。

6.2 排版效果问题

  1. 子图编号不是(a), (b),而是1(a), 1(b)?

    • 原因:某些文档类或模板(如revtex)的默认设置如此。
    • 解决:使用\captionsetup[subfigure]{labelformat=simple}可以去掉主图编号,只显示字母。或者查阅模板文档,看是否有特定命令控制。
  2. 图片位置“乱飞”,不听话?

    • 原因:LaTeX浮动体(figuretable)的定位算法(htbp)是为了优化整体版面,而非精确固定位置。
    • 解决
      • 轻度控制:使用位置参数[H](需要float宏包,\usepackage{float})。这会强制图片位于代码书写的位置(Here),但可能导致页面留下大片空白,慎用。
      • 接受浮动:这是LaTeX的哲学。相信它的排版算法,用\label\ref正确引用,不要纠结于绝对位置。在最终稿中,位置通常是合理的。
      • 使用\clearpage:在重要的图/表前后使用\clearpage命令,可以强制LaTeX输出所有等待排版的浮动体,有时能起到控制作用。
  3. 并排的图片高度不一致,导致说明文字不对齐?

    • 原因:图片原始高度不同,且未做对齐处理。
    • 解决
      • 使用subfigure环境的[b](底部对齐)或[t](顶部对齐)选项,让说明文字对齐。
      • 如果希望图片顶部也对齐,可以尝试用\vspace在较短的图片下方手动添加一些垂直空白,但这属于“硬调整”,不够优雅。更好的办法是在图像处理软件中提前将图片裁剪或画布调整为相同的高度。

6.3 与期刊模板的兼容性问题

许多学术期刊提供自己的LaTeX模板,这些模板可能修改了浮动体和说明的默认行为。

  • 首要原则优先遵循模板的说明和示例。仔细阅读模板的.tex示例文件,看他们是如何处理多图并排的。
  • 如果模板使用了subfig宏包:那么你可能需要将文中的subcaption语法改为subfig的语法(通常是\subfloat命令),或者尝试在加载模板后,用\usepackage{subcaption}覆盖,但这可能有风险。
  • 检查冲突:如果编译出错,尝试注释掉你添加的\usepackage{caption}\usepackage{subcaption},看是否是模板自带宏包冲突。有时模板会自己加载这些宏包。

7. 完整可复现的实战示例

下面提供一个从零开始的完整示例,你可以直接复制到一个新的.tex文件中进行编译测试。

\documentclass[11pt, a4paper]{article} % 文档类 \usepackage[utf8]{inputenc} % 编码 \usepackage{graphicx} % 插入图片 \usepackage{caption} % 增强说明样式 \usepackage{subcaption} % 子图功能 \usepackage{blindtext} % 仅用于生成填充文本 % 统一设置图片和子图的说明样式 \captionsetup[figure]{font=small, labelfont=bf, labelsep=period} \captionsetup[subfigure]{font=scriptsize, labelfont=rm, justification=centering} \title{LaTeX多图并排排版实战指南} \author{Your Name} \date{\today} \begin{document} \maketitle \section{引言} \blindtext[1] % 生成一段随机文本 % --- 示例1:基础两图并排 --- \section{基础两图并排示例} \blindtext[1] \begin{figure}[htbp] \centering \begin{subfigure}[b]{0.48\textwidth} \centering \includegraphics[width=0.95\linewidth]{example-image-a} % 使用example-image-*,任何TeX发行版都有 \caption{系统架构图。展示了主要组件及其交互关系。} \label{fig:exp1-a} \end{subfigure} \hfill \begin{subfigure}[b]{0.48\textwidth} \centering \includegraphics[width=0.95\linewidth]{example-image-b} \caption{数据流程图。描述了信息在系统中的传递路径。} \label{fig:exp1-b} \end{subfigure} \caption{系统设计与数据流概览。左图(\ref{fig:exp1-a})为架构,右图(\ref{fig:exp1-b})为流程。} \label{fig:exp1-total} \end{figure} 如图\ref{fig:exp1-total}所示,我们分析了整个系统。具体来说,组件A(见子图\ref{fig:exp1-a})负责处理输入,而数据流向(见子图\ref{fig:exp1-b})最终到达输出端。 % --- 示例2:2x2图片矩阵 --- \section{复杂布局:2x2图片矩阵} \blindtext[1] \begin{figure}[htbp] \centering % 第一行 \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=\linewidth]{example-image-a} \caption{实验组结果-初期} \label{fig:matrix-a} \end{subfigure} \hfill \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=\linewidth]{example-image-b} \caption{对照组结果-初期} \label{fig:matrix-b} \end{subfigure} \\[6pt] % 增加行间距 % 第二行 \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=\linewidth]{example-image-c} \caption{实验组结果-末期} \label{fig:matrix-c} \end{subfigure} \hfill \begin{subfigure}{0.48\textwidth} \centering \includegraphics[width=\linewidth]{example-image-a} \caption{对照组结果-末期} \label{fig:matrix-d} \end{subfigure} \caption{不同条件下实验结果的对比矩阵。从上到下为时间维度,从左到右为组别维度。} \label{fig:matrix-total} \end{figure} 通过对比图\ref{fig:matrix-a}与\ref{fig:matrix-c},可以明显看出实验组随时间的变化趋势。 \end{document}

使用说明:

  1. 将上述代码保存为multi_figures.tex
  2. 使用任何LaTeX编辑器(如TeXstudio, Overleaf, VS Code with LaTeX Workshop)进行编译。
  3. 编译时,由于使用了\label\ref进行交叉引用,务必编译两次(点击两次编译按钮或运行两次pdflatex)才能看到正确的引用编号。
  4. 示例中使用的example-image-a,b,cmwe(最小工作示例)宏包提供的虚拟图片,任何标准LaTeX环境都有,方便测试。在实际使用时,请将文件名替换为你自己的图片文件(如\includegraphics{my_photo.png}),并确保图片路径正确。

这个示例涵盖了从宏包加载、样式设置、基础并排、复杂矩阵到交叉引用的完整流程,你可以以此为模板,快速应用到自己的文档中。记住,清晰的图表排版是专业文档不可或缺的一部分,花点时间掌握这些技巧,能让你的工作成果更加出色。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询