图没有出现在你写它的位置;表格跳到了几页之后。这不是 LaTeX 的 bug,而是因为 figure 和 table 是 浮动体(floating objects)。LaTeX 会把图表从正文流中分离出来,让它们“浮动”到页面版式最合适的位置。本页依次说明你能在多大程度上控制这种位置:[htbp] 中的 位置指定符、阻断浮动流的 \FloatBarrier 和 \clearpage、并排放置两幅图的方法,以及让正文环绕图片的 wrapfig 宏包。
什么是浮动体
图或表跨过分页时会显得很难看;不能这一页放一半,下一页再放剩下的一半。因此 LaTeX 会把每个图表当作一个 整体盒子,在排好一段正文之后,自动为它选择位置:页面顶部、页面底部,或者只放浮动体的专用页。这就是浮动体。标准的浮动环境有 figure 和 table 两个,分别用于图和表。
浮动体有好处,也有让人困惑的一面。好处是:图表不会被分页切开,编号(“Figure 1”、“Table 2”)以及通过 \caption、\label、\ref 进行的交叉引用都会自动保持一致。让人困惑的是:写在源码中的位置和实际输出位置会不同。LaTeX 的设计基于这样一个思路:既然正文里可以用 \ref{fig:foo} 写出“见 Figure 1”,图本身就不必紧挨着那句话。所以原则是 按编号引用,而不是按位置指示。用 \input 组织文件以及图像本身的制作放在其他页面讲;这里专注于浮动体最终落在哪里。
[htbp] 位置指定符
figure 和 table 环境可以接收一个称为 位置指定符(placement specifier)的可选参数:像 \begin{figure}[htbp] 这样写在方括号中,用来告诉 LaTeX 可以使用哪些位置。可组合的字母如下。
| 指定符 | 含义 | 备注 |
|---|---|---|
h | here | 靠近正文中的当前位置。不能单独使用 h;LaTeX 会自动补上 t |
t | top | 文本页顶部 |
b | bottom | 文本页底部 |
p | page | 单独的浮动页,只放浮动体,没有正文 |
! | override | 仅对这个浮动体忽略数量限制和浮动体/正文比例限制 |
H | 真正就在这里(不浮动) | 由 float 宏包提供;固定在原处,不再浮动 |
如果省略指定符,article、book 等类会使用默认的 tbp(注意没有 h)。写多个字母时,LaTeX 会在这些允许位置中寻找能放下的地方。有两个重要陷阱。第一,单独的 h 基本会被忽略:LaTeX 不允许裸 h,会悄悄补上 t,所以写 [h] 也常常会跳到页顶。真正需要“就在这里”时,请使用后面介绍的 float 宏包提供的 [H]。
第二,指定符中字母的顺序不会改变 LaTeX 尝试位置的顺序。无论写 [bt] 还是 [tb],LaTeX 尝试候选位置的顺序都相同(大致是当前位置 → 顶部 → 底部 → 浮动页)。把这些字母理解为允许位置的*集合*即可。LaTeX 还会按浮动体在 源码中出现的顺序 处理,因此后面的图也可能越过前面的图先出现。实际使用时不要限制得太死:像 [tbp] 或 [htbp] 这样允许的范围越宽,LaTeX 越容易把浮动体放在附近。缩小到单个字母(尤其是 [h])反而容易漂得更远。
\begin{figure}[htbp]
\centering
\includegraphics[width=0.6\textwidth]{plot}
\caption{実験結果}
\label{fig:result}
\end{figure}
図~\ref{fig:result} に結果を示す。在这个例子中,[htbp] 允许当前位置、页顶、页底或浮动页中的任意位置,由 LaTeX 选择最佳位置。用于居中图片的 \centering、用于标题和编号的 \caption、用于引用的 \label,都是浮动体中常见的内容。正文用 図~\ref{fig:result} 按编号 引用它,所以即使图片输出在稍远的位置,文字也仍然成立(~ 是不换行空格,用来避免词和编号在行尾分开)。
强制就在这里 — [H]
如果确实必须让浮动体“就在我写的位置”,请在导言区加载 float 宏包,并使用大写 [H]。[H] 不是普通的位置字母:它会完全关闭浮动,把图或表 固定 在当前位置。它的行为基本就像在那里直接放下一个大盒子。
\usepackage{float}
% ...
\begin{figure}[H]
\centering
\includegraphics[width=0.6\textwidth]{diagram}
\caption{処理の流れ}
\end{figure}不过应把 [H] 当作最后手段。固定浮动体时,如果页脚放不下,可能会留下 大片空白,或者把浮动体推到下一页页首,使当前页底部变空。通常信任 LaTeX,并用较宽松的 [htbp],结果反而更整洁。[H] 只适合那些确实必须出现在正文某个精确位置的小图表,例如步骤说明图。也可以用 \floatplacement{figure}{H} 把 [H] 设为全文默认,但基于上述原因并不推荐。
阻断浮动流 — \FloatBarrier 与 \clearpage
最让人头疼的浮动体问题,是某一节的图放不进本节,结果 漂到下一节(或下一章)。当第 2 节的 Figure 3 出现在第 3 节正文中间时,读者会很困惑。要阻止这种情况,需要放置一个浮动体不能越过的 屏障(barrier)。
这个屏障就是 placeins 宏包提供的 \FloatBarrier。在放置这条命令的位置,所有尚未处理的浮动体都会先在它之前输出,之后的浮动体也不能越过它。若想按节隔开浮动体,可以在每个 \section 前写 \FloatBarrier,或者加载 \usepackage[section]{placeins},让它自动在每个 \section 开头插入屏障。
\usepackage{placeins}
% ...
\section{実験}
% ... 図や表 ...
\FloatBarrier % ここより先へフロートを越えさせない
\section{考察}\clearpage 与它相近但并不相同,差别在于是否分页。\clearpage 会 输出所有待处理浮动体,然后开始新页;而 \FloatBarrier 只输出浮动体,不强制分页。因此若只想在同一页内设置屏障,用 \FloatBarrier;若在章末等位置可以整页分开,用 \clearpage。[section] 屏障默认很严格,会禁止浮动体稍微超出本节范围;可用 [above] 和 [below] 选项放宽。
再深入一点,LaTeX 的自动放置会遵循一组 浮动体放置参数:这些内部数值以比例表示,决定页面中允许由浮动体占据多少部分。当其他方法都不奏效时,可以用它们做最后调整(不过多数情况下应先重新检查 [htbp])。
| 参数 | 默认值 | 含义 |
|---|---|---|
\topfraction | 0.7 | 页面顶部可由浮动体占据的最大比例 |
\bottomfraction | 0.3 | 页面底部可由浮动体占据的最大比例 |
\textfraction | 0.2 | 文本页中必须保留为正文的最小比例 |
\floatpagefraction | 0.5 | 生成独立浮动页所需的最小填充比例 |
topnumber | 2 | 页面顶部最多可放置的浮动体数 |
bottomnumber | 1 | 页面底部最多可放置的浮动体数 |
totalnumber | 3 | 单页最多可放置的浮动体数 |
比例参数可用 \renewcommand{\topfraction}{0.85} 修改,整数计数器可用 \setcounter{totalnumber}{5} 修改。例如提高 \topfraction、降低 \textfraction,就能让页面顶部容纳更多图表,减少“这里放不下,所以推到下一页”的情况。前面提到的 ! 指定符实际上就是这种调节的局部版本:它告诉 LaTeX 仅对这一个浮动体忽略这些限制。
并排放置两个对象
经常会想把两幅图(或两个表)左右并排。由于浮动体内部可以放任意内容,基本思路是 在一个 figure 中放两个并排的盒子。只用原生 LaTeX 的做法是 minipage;如果要给子图编号为 (a)、(b),则使用 subcaption 宏包。
minipage 是创建指定宽度“小页面”的环境。把两个 minipage 横向放置,并在中间插入 \hfill(可伸缩的水平空白),它们就会分布到左右两侧。诀窍是把每个宽度设为略小于正文宽度的一半,例如 0.48\textwidth,使总宽度略低于全文宽。
\begin{figure}[htbp]
\centering
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\linewidth]{left}
\caption{左の図}
\label{fig:left}
\end{minipage}
\hfill
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\linewidth]{right}
\caption{右の図}
\label{fig:right}
\end{minipage}
\end{figure}在这个例子中,两个宽度为 0.48\textwidth 的 minipage 位于 figure 内部,中间的 \hfill 把剩余空白向外推,使它们贴近两侧边界。在每个 minipage 内,\linewidth 表示该 minipage 的宽度,所以 \includegraphics[width=\linewidth] 会让图片填满盒子。由于每个 minipage 都有自己的 \caption,它们会得到 不同编号,如 “Figure 1”、“Figure 2”。如果想把这对图当作一幅图,只在 figure 直属位置放一个 \caption。
如果要把左右两幅编号为 同一幅图的子图,如 “Figure 2(a)”、“Figure 2(b)”,请使用 subcaption 宏包的 subfigure 环境(写法很像 minipage,内部的 \subcaption 或 \caption 会生成 (a)/(b) 标签)。子图和 caption 的详细用法见单独的 “Captions & subfigures” 页面。并排放置两个表的思路相同:在每个 minipage 中放一个 tabular。
让正文环绕图片 — wrapfig
如果想让正文环绕在小图的一侧,也就是杂志文章中常见的布局,请使用 wrapfig 宏包的 wrapfigure 环境(表格则用 wraptable)。语法如下:
\usepackage{wrapfig}
% ...
\begin{wrapfigure}[12]{r}[34pt]{0.4\textwidth}
\centering
\includegraphics[width=0.38\textwidth]{portrait}
\caption{人物像}
\end{wrapfigure}它有四个参数,其中两个是必需的。{r} 是 位置(放在哪一侧),最后的 {0.4\textwidth} 是 图的宽度。中间可选的 [12] 是要环绕的 行数,可选的 [34pt] 是 伸出量(overhang),即图向页边距伸出多少。位置字母成对出现:小写表示固定在当前位置,大写表示允许作为浮动体浮动。
| 字母 | 侧边 | 备注 |
|---|---|---|
r / R | right | r = 原处,R = 可浮动 |
l / L | left | l = 原处,L = 可浮动 |
i / I | inner | 朝向装订侧;用于 twoside 文档 |
o / O | outer | 远离装订侧;用于 twoside 文档 |
在这个例子中,宽度为 0.4\textwidth 的图放在正文 右侧,接下来的 12 行 从它左边环绕;[34pt] 让它伸入右侧页边距。如果省略行数 [12],wrapfig 会根据图的高度自行估算环绕行数(估算不准、环绕变乱时,显式给出会更稳定)。双面打印时如果希望图放在远离装订的一侧,可使用 o(outer),它会在左右页之间自动切换。
wrapfig 很方便,但也 相当挑剔,因此要记住它的注意事项。手册的大意是:
- 不要在列表内部、列表前后紧邻处使用。 避免放在
itemize、enumerate、description等列表环境内部或它们紧挨着的位置。 - 不要让它跨过分页。 放置环境时要确保环绕部分不会被分页切开;避开页面边界附近。
- 不要让标题或大型公式环绕它。 为了版面效果,只让普通正文环绕;节标题和陈列公式效果很差。
- 最好从段落边界开始,而不是段落中间。 在
minipage或parbox中使用时,还要确保环绕在该组结束前完成。
如果环绕效果不稳定,通常把图稍微缩窄、明确写出行数,或把开始位置移动一个段落就能解决。若仍然排不整齐,放弃 wrapfig,改用普通浮动体([htbp],放在正文上方或下方),最终可能更易读。