\begin{figure}라고 쓴 자리에 그림이 나오지는 않습니다. LaTeX는 그림을 본문 흐름에서 떼어 내어 상자들의 대기열에 맡겨 두고 다니다가, 페이지 사정이 맞는 지점에서야 비로소 내려놓습니다. 이것이 플로트이고, [htbp]의 네 글자는 “어디에 내려놓아도 되는가”를 알려 주는 허가증일 뿐입니다. 이 구조를 모른 채 [h]만 계속 쓰면 그림은 오히려 더 멀리 날아갑니다. 이 페이지에서는 플로트가 움직이는 이유, [htbp] 각 글자의 실제 의미, [H]와 [h!]의 결정적 차이, \FloatBarrier와 \clearpage로 막는 법, 배치 매개변수, 그리고 ! LaTeX Error: Too many unprocessed floats.가 나오는 진짜 조건을 다룹니다.
그림이 쓴 자리에 나오지 않는 이유
그림이나 표가 페이지 나눔에 두 동강 나면 읽을 수 없습니다. 절반은 여기, 나머지는 다음 페이지에 둘 수는 없습니다. 그래서 LaTeX는 그림과 표를 나눌 수 없는 하나의 상자로 다루고, 본문 조판이 어느 정도 진행된 뒤 페이지 위쪽, 아래쪽, 또는 플로트만 모은 전용 페이지 가운데 한 곳을 골라 내려놓습니다. 이것이 플로트이며 표준 환경은 figure와 table 둘입니다. 위치를 손으로 정하게 하는 대신 배치를 최적화 문제로 푼다는 점은 줄바꿈을 다루는 방식과 똑같습니다. TeX의 설계 사상이 그대로 드러나는 대목입니다.
이 설계에는 양면이 있습니다. 한쪽은 그림이 결코 갈라지지 않고, 번호(“그림 1”, “표 2”)와 \caption・\label・\ref를 통한 상호 참조가 저절로 맞춰진다는 점입니다. 다른 쪽은 쓴 위치와 나오는 위치가 어긋난다는 점입니다. 두 번째는 결함이 아니라 전제입니다. 본문에서 “그림 1 참조”라고 번호로 쓸 수 있는 이상 그림이 그 문장 옆에 있을 필요는 없습니다. 그래서 원칙은 위치가 아니라 번호로 참조하기입니다. LaTeX는 플로트를 소스에 나타난 순서로 처리하므로 뒤의 그림이 앞의 그림을 앞질러 먼저 나오기도 합니다. 본문에 “위 그림”, “아래 그림”이라고 쓰는 것이 위험한 이유가 바로 이것입니다.
[htbp]의 h・t・b・p가 실제로 뜻하는 것
figure와 table은 선택 인수로 배치 지정자를 받습니다. \begin{figure}[htbp]의 대괄호가 그것으로, “이 위치라면 놓아도 된다”는 허가의 집합을 LaTeX에 건넵니다. 아무것도 쓰지 않으면 article이나 book의 기본값 tbp가 적용되는데, 여기에 h는 들어 있지 않습니다. 즉 지정자를 생략한 그림은 애초에 “그 자리”를 후보로 두지 않은 셈입니다.
| 지정자 | 의미 | 실제 동작 |
|---|---|---|
h | here | 단독으로는 쓸 수 없음. LaTeX가 t를 더하고 LaTeX Warning: 'h' float specifier changed to 'ht'.를 냅니다 |
t | top | 본문 페이지 위쪽. 기본값으로 최대 2개, 본문 높이의 70%까지 |
b | bottom | 본문 페이지 아래쪽. 기본값으로 1개, 본문 높이의 30%까지 |
p | page | 본문 없는 플로트 전용 페이지. 50% 이상 채워질 때만 만들어짐 |
! | override | 이 플로트에 한해 개수와 높이 제한을 무시. 위치 후보가 늘지는 않음 |
H | float 패키지 전용 | 아예 플로트로 만들지 않음. 패키지가 없으면 ! LaTeX Error: Unknown float option 'H'. |
많은 해설이 [h]를 “무시된다”로 넘기지만, 실제로는 LaTeX가 경고를 내며 조용히 고쳐 씁니다. \begin{figure}[h]를 조판하면 로그에 LaTeX Warning: 'h' float specifier changed to 'ht'.가 남고 지정은 ht로 처리됩니다. [h!]도 마찬가지여서 LaTeX Warning: '!h' float specifier changed to '!ht'.가 됩니다. 이 경고를 읽으면 그림이 왜 위로 날아갔는지 그 자리에서 알 수 있습니다. 또 하나의 오해는 글자 순서입니다. [bt]라고 쓰든 [tb]라고 쓰든 시도 순서는 달라지지 않습니다. 지정자는 순서가 아니라 허용한 위치의 집합이고, LaTeX 내부의 시도 순서는 고정되어 있습니다. 실무의 결론은 선택지를 좁히지 않는 것입니다. [tbp]나 [htbp]처럼 넓게 허용할수록 그림은 가까이 떨어지고, [h] 한 글자로 좁힐수록 멀리 날아갑니다.
\begin{figure}[htbp]
\centering
\includegraphics[width=0.6\textwidth]{plot}
\caption{Measured values against the model}
\label{fig:result}
\end{figure}
% refer by number, not by position; ~ keeps word and number on one line
See Figure~\ref{fig:result} for the result.[H]와 [h!]의 차이: 한쪽은 플로트조차 아니다
[H]는 “[h!]보다 더 강한 here”가 아닙니다. 애초에 플로트 기구를 거치지 않습니다. float 패키지는 LaTeX 내부의 \@xfloat를 갈아 끼우고, 지정자 첫머리에 H가 보이는 순간 다른 코드로 갈라집니다. 즉 H는 배치 지정자로 평가되지 않으며, 그림이나 표는 그저 큰 상자로 그 자리에 조판됩니다. 그래서 float를 불러오지 않고 [H]라고 쓰면 ! LaTeX Error: Unknown float option 'H'.로 멈춥니다. 반면 [h!]는 끝까지 플로트인 채로 내부 제한만 무시할 뿐이라, 놓지 못하면 여느 때처럼 흘러갑니다.
실제로 조판해 보면 차이가 한눈에 보입니다. 같은 자리에 본문 높이의 절반쯤 되는 그림을 [H]와 [!h]로 각각 놓아 보면, [H] 그림은 꿈쩍하지 않고 들어가지 못하는 만큼 주변 본문까지 함께 다음 페이지로 밀려납니다. [!h] 그림은 경고를 낸 뒤 뒤따르는 본문을 앞질러 다음 페이지 맨 위로 날아갑니다. 즉 [H]는 “무조건 여기, 대신 페이지를 나눈다”이고, [!h]는 “되도록 여기, 안 되면 움직인다”입니다. [H]는 절차도나 알고리즘 흐름도처럼 문장의 순서와 묶인 작은 그림에 어울리지만, 큰 그림에 쓰면 앞 페이지 아래 절반이 통째로 비게 됩니다. \floatplacement{figure}{H}로 문서 전체 기본값으로 삼을 수도 있으나, 대가는 거의 언제나 많은 여백입니다.
\usepackage{float}
% ...
\begin{figure}[H] % not a float any more: pinned, page breaks around it
\centering
\includegraphics[width=0.6\textwidth]{diagram}
\caption{Processing pipeline}
\end{figure}플로트를 막기: \FloatBarrier와 \clearpage
가장 화가 나는 경우는 어떤 절의 그림이 그 절에 다 들어가지 못하고 다음 절로 흘러드는 것입니다. 2절의 그림 3이 3절 본문 중간에 나타나면 독자는 자기가 어디에 있는지 놓칩니다. 이를 막는 것이 placeins 패키지의 \FloatBarrier이며, Donald Arseneau가 만들어 퍼블릭 도메인으로 공개했습니다. 절 단위로 막고 싶다면 각 \section 앞에 두거나, \usepackage[section]{placeins}를 불러오면 모든 \section 첫머리에 자동으로 삽입됩니다.
여기서 바로잡아야 할 통설이 있습니다. “\FloatBarrier는 페이지를 나누지 않는다”는 말은 틀렸습니다. placeins의 소스를 읽어 보면, \FloatBarrier는 대기 중인 플로트가 남아 있는 동안 \newpage를 내고 자기 자신을 다시 부르며, 그래도 비워지지 않으면 \clearpage로 전환합니다. 실제로 아래쪽 [b]로 지정한 큰 그림이 대기 중인 상태에서 장벽을 통과시키면, 그림은 다음 페이지에 나오고 본문은 그다음 페이지부터 이어집니다. 페이지가 둘 진행됩니다. 페이지를 건드리지 않는 것은 대기 플로트가 하나도 없을 때뿐입니다. 따라서 둘의 진짜 차이는 “페이지를 나누느냐 마느냐”가 아니라 “무조건 나누느냐(\clearpage), 필요할 때만 나누느냐(\FloatBarrier)”입니다.
\usepackage{placeins} % or [section] to barrier every \section
\usepackage{afterpage}
% ...
\section{Experiment}
% ... figures and tables ...
\FloatBarrier % nothing may cross this line
\section{Discussion}
% flush pending floats at the END of the current page, not right here
\afterpage{\clearpage}\clearpage의 효과는 원하지만 지금 이 자리에서 페이지가 나뉘면 곤란한 상황에는 afterpage 패키지의 \afterpage{\clearpage}가 잘 듣습니다. 지금 조판 중인 페이지가 자연스럽게 끝난 지점에서 \clearpage를 실행해 주므로 본문 한가운데에 구멍이 생기지 않습니다. 더 국소적인 도구로는 \suppressfloats[t]가 있습니다. “이 페이지 위쪽에는 더 이상 플로트를 두지 말라”는 뜻이며, placeins의 [section] 옵션도 제목 바로 뒤에서 내부적으로 이것을 씁니다. 참고로 [section]은 기본적으로 꽤 엄격해서 플로트가 절 시작 위쪽으로 올라가는 것조차 금합니다. 완화하려면 [above]나 [below] 옵션을 붙입니다.
플로트 배치 매개변수: “안 들어간다”는 말의 진짜 이유
“위쪽에 들어갈 만한데 왜 안 들어가지?”의 답은 대개 배치 매개변수에 있습니다. LaTeX는 페이지 가운데 얼마를 플로트에 내어 줄지를 비율과 개수로 들고 있으며, article 클래스의 기본값은 \topfraction = 0.7, \bottomfraction = 0.3, \textfraction = 0.2, \floatpagefraction = 0.5, 그리고 topnumber = 2, bottomnumber = 1, totalnumber = 3입니다. 즉 본문 높이의 70%를 넘는 그림은 어떤 경로로도 위쪽에 갈 수 없습니다. 지정자에 [t]만 적혀 있다면 그 그림은 갈 곳을 잃고 끝없이 뒤로 밀립니다.
| 매개변수 | article 기본값 | 무엇을 정하는가 |
|---|---|---|
\topfraction | 0.7 | 페이지 위쪽을 플로트가 차지해도 되는 최대 비율 |
\bottomfraction | 0.3 | 페이지 아래쪽을 플로트가 차지해도 되는 최대 비율 |
\textfraction | 0.2 | 본문 페이지에 반드시 남겨야 하는 본문의 최소 비율 |
\floatpagefraction | 0.5 | 플로트 전용 페이지를 만들기 위해 필요한 최소 채움 정도 |
topnumber | 2 | 페이지 위쪽에 둘 수 있는 플로트 최대 개수 |
bottomnumber | 1 | 페이지 아래쪽에 둘 수 있는 플로트 최대 개수 |
totalnumber | 3 | 한 페이지 전체에 둘 수 있는 플로트 최대 개수 |
\dbltopfraction | 0.7 | 2단 figure*가 페이지 위쪽을 차지해도 되는 최대 비율 |
비율은 \renewcommand{\topfraction}{0.85}, 정수는 \setcounter{totalnumber}{5}로 바꿉니다. \topfraction을 올리고 \textfraction을 내리면 위쪽에 더 많은 그림과 표가 올라가고 “안 들어가니 뒤로”라는 밀어내기가 줄어듭니다. 사실 [htbp]의 !는 이 조정의 한 번뿐인 국소판입니다. 2단 조판에는 별도의 값이 있어 figure*는 \dbltopfraction을 따릅니다. 여기서 숫자보다 중요한 사실이 하나 있습니다. 2단의 figure*는 t와 p에만 놓일 수 있습니다. LaTeX 내부에는 단 전체를 가로지르는 플로트용 아래쪽 목록 자체가 없고, 기본 지정자도 tp입니다. \begin{figure*}[hb]라고 써도 경고조차 없이 조용히 페이지 위쪽으로 돌려집니다.
Too many unprocessed floats: 한계는 18이 아니라 52
대기열이 넘치면 ! LaTeX Error: Too many unprocessed floats.가 납니다. 널리 퍼진 “플로트는 최대 18개”라는 숫자는 이미 낡았습니다. latex.ltx는 확실히 \bx@A부터 \bx@R까지 상자 18개를 확보하지만, e-TeX을 쓸 수 있는 환경(오늘날 쓰이는 엔진은 모두 그렇습니다)에서는 이어서 \bx@S~\bx@Z와 \bx@AA~\bx@ZZ를 더해 모두 52개가 됩니다. 이 확장은 LaTeX 2015/10/01 릴리스에 들어갔습니다. 실제로 어디에도 놓일 수 없는 플로트를 늘어놓고 시험하면 오류는 정확히 53번째에서 납니다.
오류가 났다고 서둘러 그림을 줄일 필요는 없습니다. 같은 시기에 들어온 \extrafloats{n}을 프리앰블에 적으면 상자를 더 확보할 수 있습니다. 실측에서 52개에서 넘치던 문서는 \extrafloats{40}을 더하자 곧바로 오류가 사라졌습니다. 다만 상자 부족은 대개 원인이 아니라 증상입니다. 넘치는 문서는 보통 놓을 수 없는 플로트를 쌓아 두고 있습니다. 본문 높이의 70%를 넘는 그림인데 지정자에 [t]만 있거나, 플로트 사이에 본문이 거의 없어 페이지를 나눌 기회 자체가 생기지 않는 경우입니다. 지정자를 [htbp]로 넓히고 군데군데 \clearpage를 넣어 비워 주는 편이 근본 해결에 더 가깝습니다. 이와 관련해 LaTeX Warning: Float too large for page by ...pt는 “이 그림은 한 페이지에 들어가지 않아 전용 페이지로 내보냈다”는 뜻으로, 그림을 줄일지 용지를 바꿀지 판단할 근거가 됩니다.
% loosen the layout rules for the whole document
\renewcommand{\topfraction}{0.85}
\renewcommand{\textfraction}{0.1}
\renewcommand{\floatpagefraction}{0.75}
\setcounter{totalnumber}{5}
% allocate 40 more float boxes on top of the built-in 52
\extrafloats{40}두 그림을 나란히 놓기
플로트는 내용을 가리지 않으므로 나란히 놓기는 하나의 figure 안에 상자를 두 개 만드는 것으로 끝납니다. 순수 LaTeX에서는 minipage, 즉 지정한 너비로 “작은 페이지”를 만드는 환경입니다. 둘을 놓고 사이에 \hfill(늘어나는 수평 여백)을 끼우면 남는 공간이 바깥으로 밀려 양 끝에 붙습니다. 너비는 본문 폭의 절반보다 살짝 좁게, 0.48\textwidth 정도가 기준입니다. 합계가 \textwidth를 넘으면 Overfull \hbox가 나고 두 번째 상자가 아래로 떨어집니다.
\begin{figure}[htbp]
\centering
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\linewidth]{left}
\caption{Left panel} % its own number
\label{fig:left}
\end{minipage}
\hfill
\begin{minipage}{0.48\textwidth}
\centering
\includegraphics[width=\linewidth]{right}
\caption{Right panel} % a second, separate number
\label{fig:right}
\end{minipage}
\end{figure}각 minipage 안에서 \linewidth는 그 미니페이지의 폭을 뜻하므로, \includegraphics[width=\linewidth]라고 쓰면 상자에 꼭 맞게 들어갑니다. 이 예에서는 minipage마다 \caption을 두었기 때문에 두 장은 별개의 번호를 가진 “그림 1”과 “그림 2”가 됩니다. 하나의 그림의 (a)(b)로 만들려면 subcaption 패키지가 필요하며, 그 이야기는 자매 페이지에 맡깁니다. 2단 조판에서 본문 폭을 넘어 지면 전체로 펼치고 싶다면 figure*(표라면 table*)를 쓰되, 앞서 말한 대로 놓일 수 있는 곳은 페이지 위쪽이나 전용 페이지뿐입니다.
본문을 그림 주위로 흘리기: wrapfig
잡지에서 자주 보는 “작은 그림 옆으로 본문이 흐르는” 배치에는 wrapfig 패키지의 wrapfigure 환경(표라면 wraptable)을 씁니다. 이 역시 placeins와 같은 저자인 Donald Arseneau의 작품입니다. 인수는 넷이고 그중 둘이 필수입니다. {r}은 어느 쪽에 둘지, 마지막 {0.4\textwidth}는 그림의 폭입니다. 선택 인수 [12]는 감쌀 줄 수, 선택 인수 [34pt]는 그림이 판면 밖으로 얼마나 튀어나갈지를 뜻하는 오버행입니다. 배치 문자는 짝을 이루며, 소문자는 그 자리에 고정, 대문자는 플로트로 움직이는 것을 허용합니다.
\usepackage{wrapfig}
% [lines]{side}[overhang]{width}
\begin{wrapfigure}[12]{r}[34pt]{0.4\textwidth}
\centering
\includegraphics[width=0.38\textwidth]{portrait}
\caption{Portrait}
\end{wrapfigure}| 글자 | 쪽 | 비고 |
|---|---|---|
r / R | 오른쪽 | 소문자 r은 여기에 고정, 대문자 R은 플로트 허용 |
l / L | 왼쪽 | 소문자 l은 여기에 고정, 대문자 L은 플로트 허용 |
i / I | 안쪽(제본 쪽) | twoside 문서에서 좌우 페이지에 따라 자동으로 바뀜 |
o / O | 바깥쪽(책배 쪽) | twoside 문서에서 좌우 페이지에 따라 자동으로 바뀜 |
위 예에서는 폭 0.4\textwidth인 그림이 본문의 오른쪽에 놓이고, 이어지는 12줄이 그 왼쪽을 감싸며, [34pt]만큼 오른쪽 여백으로 튀어나갑니다. 줄 수를 생략하면 wrapfig가 그림 높이로부터 추정하는데, 어긋나면 감싸기가 흐트러지므로 무너졌을 때는 명시하는 편이 빠릅니다. 다만 wrapfig는 성질이 까다로운 패키지여서, 매뉴얼 자체가 쓸 자리를 제한하고 있습니다.
- 목록 안이나 목록 바로 앞뒤에서 쓰지 마세요.
itemize,enumerate,description내부나 그 경계에 두면 깨집니다. - 페이지 나눔을 가로지르게 하지 마세요. 감싸기가 두 페이지로 갈라지지 않는 위치에 두고, 페이지 경계 근처는 피합니다.
- 제목이나 별행 수식을 감싸게 하지 마세요. 감싸는 것은 평범한 본문으로만 한정합니다.
- 단락 중간이 아니라 단락의 경계에서 시작하세요.
minipage나parbox안에서 쓸 때는 감싸기가 그 그룹이 끝나기 전에 마무리되도록 합니다.
감싸기가 흐트러졌을 때는 그림 폭을 조금 줄이거나, 줄 수를 명시하거나, 시작 위치를 한 단락 옮기는 것 중 하나로 대개 잡힙니다. 그래도 정리되지 않으면 wrapfig를 포기하고 보통 플로트([htbp]로 본문 위나 아래)로 돌아가는 편이 결국 더 읽기 좋은 지면이 되는 경우가 많습니다. 그림의 자리가 정해졌다면, 다음은 그 그림에 번호와 설명을 붙일 차례입니다.