Pull to refresh

Диаграммы в LaTeX

Reading time 12 min
Views 26K
Многие достаточно часто сталкиваются с необходимостью создания различных диаграмм, графов, деревьев для удобного представления информации. Особенно важным этот вопрос может оказаться при создании презентаций. Большинство офисных пакетов предоставляют возможность создавать красивые диаграммы при помощи интерактивного интерфейса. А если нужно создать большую диаграмму? Или записать в ней математические формулы? Сосредоточиться на содержании, а не оформлении и расположении элементов на экране?

Преимущества использования LaTeX уже неоднократно обсуждались. Так же как и способы создания презентаций при помощи beamer и векторная графика из пакета PGF/Tikz. Но возможно ли получить в LaTeX диаграммы, не уступающие по внешнему виду полученным в больших и сложных пакетах? Один из способов предложен ниже.

Начало


Для начала нам потребуется LaTeX (для Windows подойдет MiKTeX, для Linux или Mac — TeXlive), а также пакеты beamer и tikz. Оба входят в комплект поставки MiKTeX. Скачать последние версии можно либо со страниц проектов, либо из CTAN. Также потребуются базовые знания о LaTeX, и использовании в нем этих пакетов. Поскольку beamer ориентирован на использование pdflatex, использоваться будет в основном именно PDF.

Простая диаграмма


Попробуем сделать небольшую и простую диаграмму. В качестве примера возьмем последовательное преобразование форматов при работе LaTeX: .tex > .dvi > .ps > .pdf. Допустим у нас уже есть документ, в который надо эту диаграмму поместить. В преамбуле подключаем пакет tikz и подключаем нужные библиотеки. В данном случае нам потребуются positioning и arrows, которые нужны для расположения элементов друг относительно друга и рисования стрелок между ними соответственно.
\usepackage{tikz}
\usetikzlibrary{positioning,arrows}<br>
Необходимо заметить, что при перечислении имен библиотек через запятую не допускаются пробелы. Это связано с тем, что tikz подставляет строку полностью как часть имени файла с библиотекой.
В нужном месте документа добавляем окружение tikzpicture, внутри которого перечисляются команды tikz. Каждая команда должна оканчиваться точкой с запятой. Команды могут быть вложенными, например для создания стрелки с подписью или дочерних элементов. Общий синтаксис команды:
\command [parameters] (name) {contents} arguments;
где
  • command — собственно команда;
  • parameters — параметры команды через запятую;
  • name — имя создаваемого объекта;
  • contents — содержание объекта (может включать другие объекты);
  • arguments — аргументы, например точки пути или размеры, а также другие команды (но уже без обратного слеша).
Все части, кроме самой команды, необязательны. В tikz сотни команд, интересными для нас будут path и node.
Команда \path создает «контур» в терминологии векторной графики. В качестве параметра указывается что именно следует сделать с этим контуром:
  • draw — только нарисовать контур;
  • fill — только залить;
  • fill,draw — нарисовать контур и залить;
  • use as bounding box — использовать контур как ограничение размера для картинки.
Также указать на наличие и направление стрелок <-, ->, <->, цвет, толщину линии и другие параметры, полный перечень можно прочитать в документации к пакету.
В качестве аргументов передаются координаты, через которые контур должен проходить. В tikz существует много вариантов задания координат:
  • относительные координаты точки (1,5);
  • реальные на листе, во всех форматах LaTeX (10pt, 3mm);
  • использование полярных и даже введение собственной системы координат;
  • относительно предыдущей точки ++(0,1);
  • относительно начальной точки +(-1,2);
  • относительно именованного объекта (name).
Точки, между которыми требуется провести линию разделяются оператором --. Наиболее подходящим к идеологии LaTeX является позиционирование относительно объектов. Например для рисования связи между краями объектов foo и bar достаточно выполнить команду
\path (foo) edge&nbsp(bar);<br>

Команда \node создает узел (или объект), как правило содержащий некий текст. Её параметрами могут быть стиль текста, цвет, информация о наличии, форме и цвете очертаний, расположение относительно других объектов и многие другие. Расположить узел в конкретном месте с координатами (x, y) можно при помощи аргумента at (x, y). Но наиболее интересным является расположение относительно других объектов, предоставляемое библиотекой positioning. Для его использования достаточно указать в параметрах в каком направлении относительно другого объекта должен находиться данный. Например
\node (foo) {foo};<br>
\node[right of=foo] (bar) {bar};<br>

Более подробную информацию можно получить в документации. Перечисленного вполне достаточно, чтобы создать первую несложную диаграмму. В ней должно быть 4 объекта, и 3 стрелки между ними. Реализация выглядит так
\node       (tex) {.tex};<br>
\node[right of=tex] (dvi) {.dvi};<br>
\node[right of=dvi] (ps)  {.ps};<br>
\node[right of=ps]  (pdf) {.pdf};<br>
<br>
\path[->] (tex) edge (dvi);<br>
\path[->] (dvi) edge (ps);<br>
\path[->] (ps)  edge (pdf);<br>



Улучшаем диаграмму


Первая картинка у нас уже получилась, но она совершенно не смотрится: смещенная линия текста, отсутствие рамок вокруг текста, слишком близко расположенные объекты. И это вместо красивых картинок с градиентами и прозрачностью? Диаграмму определенно стоит улучшить, и для этого мы воспользуемся заданием стилей. Стиль задается при помощи команды
\tikzstyle{name} = [parameters]
Имя стиля потом может быть передано как параметр другой команды. Для дальнейшей работы нам также потребуется подключить библиотеки shapes и shadows. Хорошей фигурой для текста будет прямоугольник со скругленными краями, который имеется в библиотеке. Для него дополнительно потребуется описать фон и контур. Прежде чем это сделать, давайте разберемся со способами задания цвета в tikz.
Цвет может задаваться названием из предопределенных в LaTeX и пакете xcolor. Также можно определить свой RGB-цвет при помощи команды
\definecolor{name}{rgb}{0.5,0.5,0.5}
Через запятую указаны RGB-компоненты и их количество от 0 до 1. Или в других системах, о чем можно подробнее прочитать в документации пакета xcolor. Также предопределенные цвета можно смешивать. Синтаксис этой операции таков:
color1!percent!color2
В результате получится цвет, содержащий percent% первого цвета и (100-percent)% второго. Если второй не указан — по умолчанию используется белый цвет. Смешивание цветов можно повторять, не сохраняя промежуточный цвет, например
red!50!black!50!white
Сначала будет получен цвет из 50% красного и 50% черного, а потом результат смешан с 50% белого. В результирующем красного и черного цветов окажется по 25%.

Теперь можем перейти непосредственно к заданию стиля
\tikzstyle{format} = [rounded rectangle,<br>
                      thick,<br>
                      minimum size=1cm,<br>
                      draw=red!50!black!50,<br>
                      top color=white,<br>
                      bottom color=red!50!black!20,<br>
                      font=\itshape,<br>
                      drop shadow]<br>
Данный стиль предписывает нарисовать прямоугольник со скругленными краями, жирной линией контура с цветом red!50!black!50, залить его используя градиент сверху вниз от белого цвета до red!50!black!20, с тенью, внутренний текст печатать курсивом.
Далее нам следует выровнять базовую линию текста. Для этого сначала разберемся, почему он оказался смещенным. Слова «tex», «ps» и «pdf» имеют разную высоту, и соответственно различным образом были отцентрованы внутри объекта. Таким образом явное задание высоты текста должно решить эту проблему.
Окружение tikzpicture также позволяет задавать параметры, которые действуют для всех команд внутри этого окружения. Воспользуемся этим и зададим в нем толщину линии связи, минимальное расстояние между объектами и параметры высоты текста.
\begin{tikzpicture}[thick,<br>
                    node distance=2cm,<br>
                    text height=1.5ex,<br>
                    text depth=.25ex]<br>
\node[format]  (tex) {.tex};<br>
\node[format,right of=tex] (dvi) {.dvi};<br>
\node[format,right of=dvi] (ps)  {.ps};<br>
\node[format,right of=ps]  (pdf) {.pdf};<br>
<br>
\path[->] (tex) edge (dvi);<br>
\path[->] (dvi) edge (ps);<br>
\path[->] (ps)  edge (pdf);<br>
\end{tikzpicture}<br>



Усложняем задачу


Теперь, когда мы получили приемлемый вариант простой диаграммы попробуем усложнить задание. Добавим в эту диаграмму способы представления данных (на экране и печатная) и возможности преобразования без промежуточных форматов. Поскольку линий на диаграмме будет немало, то стоит их подписать.
Определим другой стиль узла для способа представления данных. Пусть это будет эллипс с синим градиентом сверху вниз, темно-синим контуром и тенью. Описание стиля будет похожим на предыдущее.
\tikzstyle{format} = [ellipse,<br>
                      thick,<br>
                      minimum size=1cm,<br>
                      draw=blue!50!black!50,<br>
                      top color=white,<br>
                      bottom color=blue!50!black!20,<br>
                      drop shadow]<br>

Но при добавлении дополнительных линий возникает ещё одна проблема. Если задать путь от (tex) до (pdf) tikz по умолчанию проведет его прямой линией, что нас совершенно не устраивает. К сожалению, использовать возможности graphviz пакет пока не умеет, поэтому придется самим описывать путь вокруг элементов. Для этого будем использовать относительное задание путей.
\path[->, draw] (tex) -- +(0,2) -| (pdf);<br>
\path[->, draw] (dvi) -- ++(0,1) -- ++(3,0) -- (pdf);<br>
Первый контур начинается от узла (tex) и поднимается на 2 относительные единицы вверх. После чего продолжается вправо до образования перпендикуляра к узлу (pdf) и опускается к нему. Второй контур начинается от узла (dvi), поднимается на 1 единицу, идет вправо на 3 единицы относительно предыдущей точки, и по прямой направляется к узлу (pdf). Для добавления подписей к контурам воспользуемся вложенными командами и добавим узел к контуру:
\path[->, draw] (tex) -- +(0,2) -| node[near start] {pdf\LaTeX} (pdf);<br>

Но данная команда добавит объект таким образом, чтобы центры контура и узла совпали. Текст окажется перечеркнутым линией связи. Чтобы этого не произошло в окружении tikzpicture укажем параметр автоматического позиционирования подписей auto. Теперь описание нашей диаграммы примет вид
\begin{tikzpicture}[thick,<br>
                    node distance=3cm,<br>
                    text height=1.5ex,<br>
                    text depth=.25ex,<br>
                    auto]<br>
\node[format]       (tex) {.tex};<br>
\node[format,right of=tex] (dvi) {.dvi};<br>
\node[format,right of=dvi] (ps)  {.ps};<br>
\node[format,right of=ps]  (pdf) {.pdf};<br>
\node[medium,below of=dvi]  (screen) {screen};<br>
\node[medium,below of=ps]   (verbatim) {verbatim};<br>
<br>
\path[->] (tex) edge node {\LaTeX} (dvi);<br>
\path[->] (dvi) edge node {dvips}(ps);<br>
\path[->] (ps)  edge node {ps2pdf} (pdf);<br>
\path[->] (dvi) edge node {xdvi} (screen);<br>
\path[->] (ps) edge node[near start] {gs} (screen);<br>
\path[->] (pdf) edge (screen);<br>
\path[->] (ps) edge node {print} (verbatim);<br>
\path[->] (pdf) edge (verbatim);<br>
\path[->, draw] (tex) -- +(0,2) -| node[near start] {pdf\LaTeX} (pdf);<br>
\path[->, draw] (dvi) -- ++(0,1) -- node[near start] {dvipdf} ++(3,0) -- (pdf);<br>
\end{tikzpicture}<br>



Используем в презентации


Полученную диаграмму можно использовать как статическую картинку в статье или описании. Но для презентации часто требуется, чтобы объекты диаграммы появлялись в определенном порядке. В LaTeX для создания презентаций используется пакет beamer. Его работа строится вокруг понятия оверлеев — различных представлений одного и того же слайда. Об использовании beamer уже писали, поэтому вспомним о спецификации оверлеев. Их можно добавить практически к любой команде LaTeX, и команды tikz не исключение. Поэтому любые иллюстрации, полученные с помощью этого пакета легко разделяются на части и интегрируются с beamer. Однако сейчас команды расположены не совсем удобно для добавления оверлеев. Если потребуется, чтобы одновременно появлялись объект и все его связи с уже существующими, придется добавлять спецификации к каждой из команд. Логичнее было бы расположить команды последовательно по времени появления на слайде. На помощь тут приходит возможность группировать команды, о которой было сказано в самом начале. В команде \path можно указать узлы, которые она будет соединять. Таким образом мы можем сделать по одной команде на каждый оверлей.
\begin{frame}<br>
\frametitle{\LaTeX workflow}<br>
\begin{tikzpicture}[thick,<br>
                    node distance=3cm,<br>
                    text height=1.5ex,<br>
                    text depth=.25ex,<br>
                    auto]<br>
<br>
\path[use as bounding box] (-1,0) rectangle (10,-2);<br>
\path[->]<1-> node[filename] (tex) {.tex};<br>
\path[->]<2-> node[filename, right of=tex] (dvi) {.dvi}<br>
              (tex) edge node {\LaTeX} (dvi);<br>
\path[->]<3-> node[display, below of=dvi] (screen) {screen}<br>
              (dvi) edge node {xdvi} (screen);<br>
\path[->]<4-> node[filename, right of=dvi] (ps) {.ps}<br>
              (dvi) edge node {dvips} (ps);<br>
\path[->]<5-> (ps) edge node {gs} (screen);<br>
\path[->]<6-> node[display, below of=ps] (verbatim) {verbatim}<br>
              (ps) edge node {print} (verbatim);<br>
\path[->]<7-> node[filename, right of=ps] (pdf) {.pdf}<br>
              (ps) edge node {ps2pdf} (pdf);<br>
\path[->]<8-> (pdf) edge (screen)<br>
                    edge (verbatim);<br>
\path[->, draw]<9-> (tex) -- +(0,2) -| node[near start] {pdf\LaTeX} (pdf);<br>
\path[->, draw]<10-> (dvi) -- ++(0,1) -- node[near start] {dvipdf} ++(3,0) -- (pdf);<br>
\end{tikzpicture}<br>
\end{frame}<br>



Что получилось в результате можно посмотреть здесь.
_________
При подготовке использованы
PGF/Tikz manual
Xcolor manual
Beamer manual
The TeX workflow example
Tags:
Hubs:
+55
Comments 17
Comments Comments 17

Articles