пятница, 13 июня 2008 г.

Верстаем диплом в LaTeX: таблицы


Сегодня суровый челябинский программист расскажет еще об одной (наверное самой сложной) составной части процедуры верстки диплома - о работе с таблицами.

Сначала разберемся, какие сложности возникают при работе с таблицами. Прежде всего -это длинные таблицы, т.е. таблицы, которые не помещаются на одну страницу. По хорошему нас не должно интересовать, поместится таблица на одну страницу или нет, наша задача - набрать правильное содержимое. К счастью, LaTeX сам может переносить строки таблицы на новую страницу, снабжать ее соответствующими подписями и комментариями. Надо лишь его настроить, чем мы и займемся.


Прежде всего обратим внимание на заголовки. Заголовок таблицы размещается над нею и выравнивается по левому краю. Заголовок включает в себя:
- слово "Таблица"
- номер таблицы
- среднее тире
- название таблицы. Точка после названия НЕ ставится.

Если таблица переносится на следующую страницу, то пишется "Продолжение таблицы N", где N - номер таблицы. Шапка таблицы (заголовки столбцов) полностью дублируется на каждой странице.

Для работы с длинными таблицами я использовал пакет longtable. Он мне понравился своей кастомизируемостью и простотой. А также наличием внятной доки. Что, как сами понимаете, не может не радовать.

Начало таблицы задается, как начало окружения longtable, затем идут параметры столбцов (как и при создании обычной таблицы), затем идет заголовок таблицы:

\begin{longtable}{|p{2cm}|p{8cm}|c|c|c|c|c|c|c|c|}

\kill

\caption{\spaceПеречень, параметры и вероятностные характеристики работ СГ\label{works}\\

 


После чего располагается шапка таблицы, которая будет выведена на первой странице. От основной таблицы шапка отделяется командой \endfirsthead:

\hline

\multirowthead{2}{Код раб.} & \multirowthead{2}{Наименование работы} & \multicolumn{3}{|c|}{Продолж., дн.} & \multicolumn{3}{|c|}{Исполн., чел.} & \multirowthead{2}{$\delta_{ij},$ дн.} & \multirowthead{2}{$\Delta_{ij}, \text{дн.}^2$} \\

\cline{3-8}

& & мин. & макс. & ожид. & рук. & прогр. & лаб. & &\\

\hline

\endfirsthead

\kill

 


Не забываем после сокращений ставить точки. Нормоконтроллеры это любят. На команды \multirowthead не обращайте пока внимание, их суть я расскажу дальше.

После \endfirsthead должен идти заголовок таблицы, который отрисовывается на других страницах. Сложность возникает следующая - по умолчанию после этого заголовка выводится название таблицы, т.е. получается что-то вроде: "Продолжение таблицы 1 - О том о сем". Нам это не надо. Для подавления данного поведения пришлось применить хак. Ведь если разобраться - сложность только в том, чтобы определить "а что мы сейчас выводим: заголовок таблицы на первой страницы или заголовок таблицы на остальных страницах?" К сожалению, я не смог досканально разобраться в данном механизме и сделал следующее: если заголовок пуст - то это заголовок на второй и последующих страницах. Вместо него следуюет выводить "Продолжение таблицы N" (где N - значение счетчика таблиц). Код задания пустого заголовка:

\caption{\space}\\


Для того, чтобы это все работало, в файл G2-105-95.sty были добавлены следующие команды, переопределяющие команды управления выводом заголовков из стандартного пакета longtable:

\LTleft=\z@

\LTright=\fill



\def\LT@makecaption#1#2#3{%                                                    

  \LT@mcol\LT@cols l{\hbox to\z@{\parbox[t]\LTcapwidth{%

     \ifx#3\space    

         \sbox\@tempboxa{#1{}Продолжение таблицы \@arabic\c@table}%    

      \else

          \sbox\@tempboxa{#1{#2\captionlabeldelim{}}#3}%

      \fi

      {\box\@tempboxa\hfil}%

      \endgraf}%                                              

    \hss}}}

 


После заголовка, который будет напечатан на второй и последующих таблицах страницы, необходимо задать шапку для этих страниц. По ГОСТ шапка - наименования столбцов - на всех страницах таблицы дублируется. Таким образом, достаточно скопировать код, добавляющий шапку на первую страницу. Единственное отличие - шапка второй и последующих страниц заканчивается командой \endhead, после которой идет уже сама таблица.

В принципе, с длинными таблицами - все. Рассмотрим как задать отображение заголовков обычных таблиц, т.е. таблиц, помещенных в окружение table.

Для этого необходимо добавить в стилевой файл следующие строки:

\setlength\abovecaptionskip{2\p@}

\setlength\belowcaptionskip{1\p@}



\def\capfigure{figure}

\def\captable{table}

\long\def\@makecaption#1#2{%

  \vskip\abovecaptionskip

  \ifx\@captype\capfigure

      \centering #1~--~#2 \par

  \else

      #1~--~#2 \par

  \fi

  \vskip\belowcaptionskip}



\renewcommand{\@biblabel}[1]{#1}

 


Данный код содержит настройки вывода \caption для плавающих изображений и таблиц.

Теперь разберемся с ячейками. С ячейками в LaTeX возникает две проблемы: управление выравниванием (как по вертикали, так и по горизонтали) и многострочность. Да, стандартные средства LaTeX позволяют создавать ячейки, которые занимают несколько строк по высоте, но текст в данной ячейке все равно будет занимать только одну строку, вторая окажется пустой. Вот с этим и попробуем бороться.

Какие требования к ячейкам выдвигает нормоконтроль? Все требования не вспомню, отмечу лишь основные: текст в шапке выравнивается по центру, в столбцах с численными значениями - по центру, столбцы с ценами и суммами - по правому краю. Если надо указать максимальное значение, то в поясняющем столбце пишем "не более", а значение выравниваем по высоте так, чтобы оно было на одном уровне с "не более", т.е. по нижнему краю. Тоже самое для "не менее".

Для создания ячеек с различным отображением существует пакет makecell, для создания многострочных заголовков используется пакет multirow.

Для создания заголовка столбца (строки) таблицы используется команда \thead, аргументом которой является заголовок столбца. Причем можно явно указывать места переносов слов на новые строки. Пример использования команды:

\thead{Частное\\I-го рода}


Для создания многострочного заголовка используется команда \multirowthead. Первым аргументом команды является число строк, составляющих ячейку, вторым - текст ячейки. Пример использования команды:

\multirowthead{2}{Ожид.\\прод.}


Если многострочную ячейку нужно создать не в заголовке, а в теле таблицы, то используется команда \multirowcell. Поведение и использование аналогично приведенному выше.

Что касается выравнивания в ячейках, то для этого используется команда \makecell. Данная команда имеет первый необязательный аргумент, который задает выравнивание. Причем следует иметь ввиду, что выравнивание по вертикали единое для всей строки и указывается как необязательный параметр команда \makecell первой ячейки в строке. Это очень важно. В качестве примера приведу строку, выровненную по нижнему краю:

\hline

\makecell[b]{Минимально\\необходимые,\\не менее} & 400 & 600 &  \multirowcell{3}{от 0,4 до 1,0 включ.} \\

 


На этом разговор об оформлении таблиц можно закончить. Дело это не такое уж и сложное, но нужно просто быть внимательным. Лично я потратил много времени на отыскание таких ошибок, как забыл поставить & или \\.

Если у вас возникли вопросы по циклу статей или вообще по верстке в LaTeX - буду рад на них ответить. Пишите комментарии. Если мои статьи помогли вам сверстать диплом - тоже пишите, мне будет приятно.

Другие статьи серии:



Евгений Кирпичов написал замечательный пост о повышении читабельности Java-кода и об элементах ФП в Java. Маст-Хэв однозначно.

Подгружаем картинки с prototype - замечательная статья о том, как с помощью Prototype сделать AJAX-подгружаемые картинки.

Конкурс для разработчиков от Vkontakte.ru. Обещают принять победителя в свою команду.

Понравилось сообщение - подпишись на блог

9 комментариев:

Анонимный комментирует...

Здравствуйте. Не в тему вопрос: а нет ли в Латехе какого-нибудь пакета для создания блок-схем алгоритмов? Можно, конечно, нарисовать и рисунок вставить, но хочется более кошерно))

Unknown комментирует...

Попробуйте Metapost

Симеон комментирует...

Здравствуйте! По поводу заголовков таблиц: раз по ГОСТам шапка таблицы дублируется на каждой странице, то ваш вопрос "а что мы сейчас выводим: заголовок таблицы на первой странице или заголовок таблицы на остальных страницах?" не имеет смысла (если я правильно все понял).

Лично я делаю вот такие заголовки:

\begin{longtable}[h]{разметка столбцов}
\caption{Заголовок}\label{Метка}\\
\hline
ШАПКА\\
\hline\endfirsthead
\multicolumn{Кол-во столбцов}{l}{Продолжение таблицы \ref{Метка}}\\
\hline
Повтор ШАПКИ\\
\endhead
Тело таблицы
\end{longtable}

Unknown комментирует...

Да, у вас интересное решение.

Unknown комментирует...

Здравствуйте. В своей работе набираю длинные таблицы с помощью пакета longtable. Мне необходимо явно задавать ширину каждой колонки (заголовок таблицы оформляю как \begin{longtable}{|p{5cm}|…), и в то же время для каждой колонки я хочу указывать выравнивание по вертикали и горизонтали (в том числе имеются ячейки с многострочным текстом). Использование команд \makecell и \makecell для каждой строки или же указание выравнивания с помощью \parbox является неэффективным в силу большого объема таблицы. Подскажите, каким образом я могу описать в шапке таблицы выравнивание текста в ее ячейках? Буду признателен также за подсказку места поиска решения моей проблемы. (мой уровень пользования Latex’ом недостаточно высок, но несколько объёмных документов я на нём написал)

Симеон комментирует...

1) для выравнивания по вертикали нужно указать параметр "|m{ваш_размер}|"

2) для выравнивания по горизонтали я использую команду ">{}|m{ваш_размер}|". Знак ">" говорит о том, что нужно для каждой ячейки в столбце применить данный набор инструкций в фигурных скобках. Чтобы задать выравнивание именно по центру - использую набор команд: {\centering\arraybackslash}

PS. Команда \arraybackslash - необходима!!! Иначе, если сделать последнюю колонку новым типом, то при сборке будет ошибка (якобы в конце строки в данных отсутствует двойной обратный сплеш "\\")!!!

3) Чтобы заголовок таблицы был компактным и удобочитаемым - удобнее всего вынести настройки выравнивания в преамбулу документа через переопределение нового типа колонки следующим образом:

% M - наш новый тип колонки
\newcolumntype{M}{>{\centering\arraybackslash}m}
...
\begin{document}
...
\begin{longtable}[h]{|M{1.9cm}|M{0.9cm}|p{4cm}|p{6.4cm}|}
...
тело_таблицы
...
\end{longtable}


Надеюсь это то, что надо.

Unknown комментирует...

Спасибо, вы мне помогли. Проблема заключалась в незнании команды \arraybackslash.

Unknown комментирует...

А как быть, если счётчик таблиц равен всегда нулю?
Делаю таблицы в \documentclass{book}
Переопределил \caption, как:

\renewcommand{\caption}{\centering{\textbf{таблица\ \arabic{chapter}.\arabic{table}}} \\}

Всё компилится, без ошибок. Но на месте \arabic{table} всегда выводит "0"

Симеон комментирует...

http://pastebin.com/TG0VGupu
http://disk.tom.ru/6slghl4

Вот пример "на скорую руку". Все работает. Ищите конфликты в модулях.

Отправить комментарий

Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!