표의 캡션이 표에 딱 붙어 보이는 것은 착각이 아닙니다. LaTeX의 표준 클래스는 \abovecaptionskip을 10pt, \belowcaptionskip을 0pt 로 두고 있고(article, report, book 모두 같습니다), 이 기본값은 그림을 위해 조율된 것입니다. 표의 캡션은 위에 두는 것이 관례이므로 여백이 있는 쪽이 위로 가고 0인 쪽이 표에 닿습니다. “왠지 답답하다”의 정체가 이것입니다. 이 페이지는 tabular의 바깥쪽, 즉 table 환경을 통한 배치와 캡션, 지면 폭을 넘는 표를 접는 법, 가로로 돌리는 법, 그리고 표에 주석을 붙이는 threeparttable을 다룹니다. 내용 자체를 만드는 법은 “tabular 기초”와 “열 지정, 정렬 및 너비”의 몫입니다.
표가 “떠다니는” 이유 — table 환경과 tabular의 차이
표를 중간에서 페이지 나눌 수 없기 때문입니다. tabular가 만드는 것은 하나의 큰 상자 이고, 상자는 페이지 경계에서 나눌 수 없습니다. 원본의 그 자리에 두려는데 남은 공간이 부족하면 큰 빈칸이 생기거나 지면이 망가집니다. 그래서 LaTeX는 표와 그림을 부동체(float) 로 다루어 본문 흐름에서 떼어 내고, 들어갈 만한 곳으로 보냅니다. 이를 사용하는 장치가 table 환경 입니다. 그 안에 tabular를 넣고 \caption{…}으로 “표 1” 같은 번호 붙은 제목을 주며, \label{…}과 \ref{…}로 본문에서 참조할 수 있게 합니다. 본문에는 “표~\ref{tab:sales}에서 보듯”처럼 번호로 참조 하면 되고, 표가 몇 페이지 뒤로 밀리든 번호는 자동으로 맞습니다(~는 단어와 번호가 줄 끝에서 갈라지지 않게 하는 묶음 공백입니다).
\usepackage{booktabs}
\usepackage{float} % needed only for the [H] specifier
\begin{table}[htbp]
\centering
\caption{Quarterly sales}
\label{tab:sales} % \label always AFTER \caption
\begin{tabular}{@{}lrr@{}}
\toprule
Quarter & Sales & YoY \\
\midrule
Q1 & 1{,}200 & +5\% \\
Q2 & 1{,}350 & +8\% \\
\bottomrule
\end{tabular}
\end{table}
% in the body: as Table~\ref{tab:sales} shows ...배치 지정 [htbp]와 [H]의 차이
[htbp]는 허용할 위치의 집합, [H]는 부동을 그만두라는 지시 입니다. \begin{table} 바로 뒤의 대괄호에는 h(그 자리), t(페이지 위쪽), b(페이지 아래쪽), p(부동체 전용 페이지)를 나열합니다. 아무것도 쓰지 않으면 article이든 book이든 기본값은 tbp 입니다. 즉 h는 애초에 후보에 들어 있지 않습니다. 중요한 것은 쓴 순서가 시도 순서를 바꾸지 않는다 는 점입니다. LaTeX는 언제나 t→b→p 순으로 시도하므로 [htbp]와 [bpht]는 완전히 똑같이 동작합니다. 대괄호는 희망의 표명이 아니라 허가의 열거 라고 생각하십시오.
앞에 붙은 !([!ht] 등)는 “이 부동체에 한해 내부 제한을 무시하고 배치를 시도하라”는 지시이며, “여기에 놓아라”라는 뜻이 아닙니다. 그 “내부 제한”은 실제 숫자로 정해져 있습니다. article 기본값은 \topfraction = 0.7(페이지 위쪽을 부동체가 차지해도 되는 비율), \bottomfraction = 0.3, \textfraction = 0.2(본문이 최소한 차지해야 할 비율), \floatpagefraction = 0.5(부동체 전용 페이지를 만드는 하한)이고, 한 페이지에 놓을 수 있는 부동체는 위쪽 2개, 아래쪽 1개, 합계 3개입니다(\topnumber, \bottomnumber, \totalnumber). 표가 좀처럼 나오지 않는다면 대개 이 중 어느 하나에 걸린 것이고, !는 그 판정을 느슨하게 할 뿐입니다. 정말 그 자리에 고정하고 싶다면 float 패키지의 [H] 를 씁니다. \usepackage{float} 아래에서 \begin{table}[H]라고 쓰면 표는 부동을 멈추고 소스의 그 자리에 조판됩니다(그 결과 페이지 아래에 큰 빈칸이 남을 수 있습니다). H를 “떠다니지 않는 부동체”로 이해하면 사고가 줄어듭니다.
| 지정자 | 의미 | 관련 기본값 |
|---|---|---|
h | 소스의 그 위치. h 단독은 허용되지 않으며 t가 자동 보충됨 | 기본값 tbp에는 포함되지 않음 |
t | 본문 페이지의 위쪽 | \topfraction = 0.7, \topnumber = 2 |
b | 본문 페이지의 아래쪽 | \bottomfraction = 0.3, \bottomnumber = 1 |
p | 본문이 없는 부동체 전용 페이지 | \floatpagefraction = 0.5 |
! | 이 부동체에 한해 위의 비율과 개수 제한을 무시. 위치 지정이 아님 | \textfraction = 0.2, \totalnumber = 3도 대상 |
H | 부동을 멈추고 그 자리에 고정. float 패키지가 필요 | 표준 LaTeX에는 없는 지정자 |
캡션은 표 위, 그림 아래 — 그리고 \label은 \caption 뒤에
이 두 가지가 캡션 관련 사고의 대부분을 차지합니다. \caption{…}은 부동체에 번호 붙은 제목을 주며, article이면 “Table 1:”, book이면 “Table 1.1:” 같은 연속 번호 를 자동으로 붙입니다. 표와 그림은 카운터가 따로여서 번호가 섞이지 않습니다. \caption[짧은 제목]{본문 제목}처럼 선택 인수를 붙이면 표 목록 에는 짧은 쪽이, 본문에는 긴 쪽이 실립니다. 그리고 번호를 올리는 것은 \caption이므로 \label은 반드시 \caption 뒤에 두어야 합니다. 순서를 바꾸면 \ref가 이전 번호를 가리키는데, 오류도 나지 않습니다. 배치 관례는 표는 캡션을 위에, 그림은 아래에 두는 것입니다. 표는 제목을 읽고 나서 내용으로 들어가고, 그림은 보고 나서 설명을 읽는 순서의 차이입니다. LaTeX에서는 \caption을 tabular 앞 에 쓰면 위, 뒤 에 쓰면 아래에 놓입니다.
여기서 서두의 실측값이 힘을 발휘합니다. 표준 클래스의 \abovecaptionskip은 10pt, \belowcaptionskip은 0pt 입니다. 즉 여백은 캡션의 바깥쪽에만 있고, 캡션과 부동체 본체 사이에는 아무것도 들어가지 않습니다. 캡션이 아래에 오는 그림에서는 문제가 없지만, 캡션이 위에 오는 표에서는 캡션이 표에 닿습니다. 고치는 방법은 둘입니다. 기본 LaTeX라면 \setlength{\belowcaptionskip}{6pt}를 선언합니다. caption 패키지를 쓴다면 \usepackage[skip=6pt]{caption}이라고 쓰거나, \captionsetup[table]{skip=6pt}으로 표에만 지정합니다. 글꼴, 구분자, 폭 등 캡션 서식 자체를 다듬는 것도 caption 패키지의 일이며, 자세한 내용은 “캡션과 하위 그림” 페이지에 있습니다.
내용을 가운데에 두는 것은 \centering 입니다. 부동체 안에서는 center 환경(\begin{center}…\end{center})이 아니라 \centering을 쓰는 것이 정석입니다. center 환경은 앞뒤에 여분의 세로 공간을 넣지만, \centering은 선언일 뿐이라 불필요한 여백을 만들지 않습니다. 가운데가 아니라 오른쪽 끝으로 붙이고 싶다면 내용 앞에 \hfill 을 두면 가로 방향의 남는 공간이 모두 왼쪽에 모입니다. 참고로 부동체 안의 \centering은 안전 하지만, p{width} 열 안에 \centering을 쓰는 것은 이야기가 다릅니다. 그 열이 표의 마지막 열이면 행 종결자 \\가 망가져 ! Extra alignment tab has been changed to \cr.가 나옵니다. 열 지정 안에 쓰는 \centering의 처리는 “열 지정, 정렬 및 너비”가 담당합니다.
LaTeX 표의 폭이 본문을 넘칠 때
줄이기 전에 폭의 내역을 재 보십시오. l, c, r 열은 줄바꿈하지 않으므로 열이 많으면 표가 \textwidth를 넘습니다. 그런데 넘치는 부분의 정체는 대개 글자가 아니라 열 사이의 여백 입니다. 실제 사례로, 12열에 머리글 1행과 데이터 1행짜리 booktabs 표를 재면 폭 412.95pt이고, 기본 article의 \textwidth는 345pt이므로 68pt가 넘칩니다. 같은 표를 \tabcolsep = 0pt로 다시 조판하면 268.95pt 가 되어, 차이가 정확히 144pt, 곧 2 × 12열 × 6pt 입니다. 즉 표 폭의 35%는 글자가 아니라 여백 이었습니다.
이 내역을 알면 대처의 우선순위가 달라집니다. 흔히 권하는 “글자를 한 단계 줄이기”는, 같은 표에서 \small로 해도 392.77pt, \footnotesize로 해도 372.55pt 라 어느 쪽도 345pt에 미치지 못합니다. \tabcolsep은 길이이지 글꼴에 따라 변하는 값이 아니기 때문에, 글자를 줄여도 144pt의 여백은 그대로 남기 때문입니다. 반면 \setlength{\tabcolsep}{3pt}로 절반만 줄여도 340.95pt 가 되어 본문 크기 그대로 들어맞습니다. \small과 \tabcolsep = 4pt를 함께 쓰면 344.77pt입니다. 먼저 여백, 다음에 글자 크기, 마지막에 확대·축소 순으로 생각하십시오.
\usepackage{graphicx} % for \resizebox
% 1. trim the padding first -- \tabcolsep is 6pt on EACH side of EVERY column
\begingroup
\setlength{\tabcolsep}{3pt}
\begin{tabular}{@{}lrrrrrrrrrrr@{}} % @{} also removes the outer 2 x 6pt
...
\end{tabular}
\endgroup
% 2. only then consider a smaller size, or scaling as a last resort
\resizebox{\textwidth}{!}{%
\begin{tabular}{lrrrrr}
...
\end{tabular}%
}열 지정의 양 끝에 두는 @{} 도 바깥쪽 \tabcolsep을 없애 표를 본문 왼쪽 끝에 맞춰 줍니다(실측으로 정확히 2 × 6pt = 12pt). booktabs 표에서 흔히 보는 표기입니다. 그래도 들어가지 않을 때의 마지막 수단이 graphicx의 \resizebox{폭}{높이}{내용} 이고, 둘 중 하나를 ! 로 두면 비율을 유지한 채 확대·축소합니다. 다만 이것은 내용을 “스케일링” 합니다. 앞의 표를 \resizebox{\textwidth}{!}에 통과시키면 배율이 345 ÷ 412.95 = 0.836 이 되어, 본문 10pt 글자는 약 8.4pt로, \toprule의 0.8pt는 0.67pt가 됩니다. 글자도 괘선도 주변 본문과 균형이 맞지 않게 되므로 응급 조치 로 여기십시오. \resizebox 대신 adjustbox 를 쓰면 \begin{adjustbox}{width=\textwidth}…\end{adjustbox}처럼 환경으로도 쓸 수 있습니다. 행 높이를 조금 벌리고 싶다면 \renewcommand{\arraystretch}{1.2}(기본값은 1)를 쓰며, 10pt 문서의 3행 표라면 0.2 × 3 × 12pt = 7.2pt만큼 높아집니다.
여기까지 해도 들어가지 않는다면 도구를 바꿀 신호입니다. 열을 목표 폭까지 자동으로 늘이는 tabularx의 X 열이나 tabularray의 tblr는 “고급 표 환경” 페이지가 다룹니다. 행이 많아 한 페이지에 들어가지 않는 경우는 폭이 아니라 길이의 문제이므로, 페이지를 나눌 수 있는 longtable이 나설 차례입니다. “페이지를 넘기는 표” 페이지입니다. 이 둘은 이 페이지의 확대·축소나 회전보다 먼저 검토할 가치가 있습니다.
표를 가로로 돌리기 — sidewaystable과 rotatebox
세로 페이지에 도저히 들어가지 않는 큰 표는 90도 돌려 한 페이지를 다 쓸 수 있습니다. table 대신 rotating 패키지의 sidewaystable 환경 을 쓰면 됩니다. 캡션과 번호도 함께 돌고, 표 목록에도 제대로 실립니다. 양면 조판에서는 펼침면에서 자연스럽게 읽히도록 회전 방향이 자동으로 조정됩니다. 그림에는 대응하는 sidewaysfigure가 있습니다. 표의 일부만 임의의 각도로 돌리고 싶다면 역시 graphicx・rotating의 \rotatebox{각도}{내용} 을 씁니다. 머리글 셀 하나만 \rotatebox{90}{long column name}로 세우는 것이 전형적인 용법입니다(양의 각도가 반시계 방향).
\usepackage{rotating}
\usepackage{booktabs}
\begin{sidewaystable}
\centering
\caption{A wide table turned 90 degrees}
\label{tab:wide}
\begin{tabular}{@{}lrrrrrrrr@{}}
\toprule
Region & Q1 & Q2 & Q3 & Q4 & Total & Prev & Diff & Ratio \\
\midrule
East & 120 & 135 & 128 & 142 & 525 & 500 & +25 & 105\% \\
\bottomrule
\end{tabular}
\end{sidewaystable}주의해야 할 경계가 하나 있습니다. rotating이 다루는 것은 상자(box)의 회전 이고, 상자는 반드시 한 페이지 안에 들어갑니다. 따라서 여러 페이지에 걸친 가로 방향 본문 은 만들 수 없습니다. 그런 것이 필요하다면 본문 자체를 가로로 조판하는 lscape나, PDF 페이지 자체를 회전시키는 pdflscape를 씁니다. pdflscape는 PDF 뷰어가 페이지를 알아서 돌려 주므로 화면으로 읽는 문서에 특히 알맞습니다. 가로 방향이면서 여러 페이지에 걸치는 표라면 pdflscape와 longtable의 조합이 됩니다.
표에 주석 달기 — threeparttable
tabular 안에서 \footnote를 쓰면 주석이 페이지 아래로 날아가거나 아예 출력되지 않습니다. 이를 해결하는 것이 Donald Arseneau의 threeparttable 입니다. 이름 그대로 표를 제목(캡션), 본문(tabular), 주석(tablenotes)의 세 부분 으로 다루고, 주석을 표와 같은 폭으로 표 바로 아래에 놓습니다. 패키지 자체 설명에도 있듯 threeparttable은 단독으로는 부동하지 않으므로, 번호와 배치가 필요하면 전체를 table(2단 조판에서 전체 폭이 필요하면 table*)로 감쌉니다.
\usepackage{booktabs}
\usepackage{threeparttable}
\begin{table}[htbp]
\centering
\begin{threeparttable}
\caption{Yield by variety}
\label{tab:yield}
\begin{tabular}{@{}lrr@{}}
\toprule
Variety & Yield\tnote{a} & Price\tnote{b} \\
\midrule
Koshihikari & 540 & 380 \\
Akitakomachi & 520 & 360 \\
\bottomrule
\end{tabular}
\begin{tablenotes}
\footnotesize
\item[a] Kilograms per 10 a.
\item[b] Wholesale price per kilogram.
\end{tablenotes}
\end{threeparttable}
\end{table}threeparttable 환경 안에 \caption → tabular → tablenotes 순서로 놓기만 하면 됩니다. 주석 연결은 수동 입니다. 셀에 \tnote{a} 같은 표지를 놓고, tablenotes 안에 같은 기호로 \item[a] …라고 씁니다. 자동 번호로 만들지 않은 이유를 저자가 .sty 첫머리에 남겨 두었습니다. “현재로서는 주석에 자동적인 부분이 전혀 없다… \footnote에 의한 자동 번호는 매우 쓰기 어려울 것이기에 이 방식을 택했다. 특히 많은 표가 하나의 주석을 반복해서 참조하기 때문이다. 편리하고 우아한 자동 방식을 가진 사람이 있다면 기꺼이 듣겠다!” 이 패키지는 지금도 그 설계 그대로 배포되고 있습니다.
| 옵션 | 효과 |
|---|---|
para | 여러 주석을 줄바꿈 없이 한 문단으로 이어서 조판 |
flushleft | 주석의 내어쓰기를 없앰 |
online | \item 표지를 위첨자가 아니라 본문과 같은 크기로 출력 |
normal | 기본 서식으로 되돌림(문서 전체 설정을 특정 표에서만 무시) |
이 옵션들은 \usepackage[para]{threeparttable}처럼 문서 전체에 지정할 수도 있고, \begin{tablenotes}[flushleft]처럼 표마다 지정할 수도 있습니다. threeparttable은 캡션 서식 자체를 다듬지 않으므로, 제목다운 모양이 필요하면 caption 패키지와 함께 씁니다. 페이지를 넘기는 긴 표(longtable)에 주석을 붙이려면 자매 패키지인 threeparttablex를 사용하십시오.
- 표가 원하는 위치에 나오지 않을 때 — 먼저
[htbp]를 순서가 아니라 허가의 집합 으로 다시 보십시오. 그래도 움직이지 않으면\topfraction같은 제한에 걸린 것이므로[!ht]를, 정말 고정하려면float의[H]를 씁니다. - 캡션이 표에 달라붙을 때 —
\belowcaptionskip이 기본 0pt입니다.\setlength{\belowcaptionskip}{6pt}나caption패키지의skip=을 쓰십시오. - 표가 지면 폭을 넘을 때 — 먼저
\tabcolsep과@{}, 다음에\small, 마지막에\resizebox. 열을 줄바꿈해도 된다면p{width}나tabularx를 쓰십시오. - 행이 너무 많을 때 — 폭이 아니라 길이의 문제이므로
longtable. 가로 방향까지 필요하다면pdflscape와 함께 씁니다. - 셀에 각주를 달고 싶을 때 —
\footnote가 아니라threeparttable의\tnote와tablenotes.