Структурирование данных с TikZ

В современном мире нельзя представить человека, который не работает с какими бы то ни было данными. Прежде всего под данными здесь будет подразумеваться информация. При работе с информацией зачастую встаёт сразу две проблемы:

  1. Информации слишком много. Найти можно всё. Трудно выбрать действительно полезные материалы.
  2. Информацию приходится как-то структурировать, дабы получить не отрывочную, но целостную картину изучаемой области.

И если с первой проблемой справляться остаётся лишь методом перебора, то во втором случае можно прибегнуть к маленькой хитрости и обратиться к LaTeX, чем и займёмся.

Не секрет, что для работы с графикой в LaTeX принято использовать замечательный пакет, имя которому TikZ. В сегодняшнем примере постараюсь коротко объяснить как с его помощью можно составлять такую распространённую ныне вещь как майнд-карта, создавать деревья и цепочки.

Mind map

Красивых примеров майнд-карт в сети предостаточно. Дабы не выдумывать свой велосипед, предлагается взять за основу отличную карту господина Till Tantau, добавить один уровень вложенности, выровнять блоки и включить информацию о временах глагола английского языка. Разумеется, не глаголами едиными жив человек, и читатель спокойно может видоизменить карту под свои нужды.

Итоговый вариант должен быть похожим на часть изображения ниже:

MindMap

Примечание

Вместо LaTeX можно опробовать программу FreeMind, это дело вкуса.

Для наглядности (дабы сразу можно было видеть результат сделанных правок) в Linux можно использовать услуги редактора Gummi, а пользователям Emacs открыть предпросмотр командой C-c C-v.

\documentclass[a4paper]{article} % размер, класс документа
\usepackage[russian]{babel} % поддержка кириллицы
\usepackage[utf8]{inputenc} % кодировка UTF-8
\usepackage{tikz} % подключить пакет TikZ
\usetikzlibrary{mindmap,trees} % библиотеки TikZ
\usepackage{verbatim} % нужен, если включать блок comment

\begin{document} % начало документа
\pagestyle{empty} % не нумеровать страницы

\begin{comment} % комментарий
:Title: Времена английских глаголов
:Tags: Mindmap
:Author: me
\end{comment} % конец комментария

\begin{tikzpicture} % начало блока TikZ
  \path[mindmap,
  % положение узлов 1 уровня относительно друг друга
  level 1 concept/.append style={level distance=120,sibling angle=150},
  grow cyclic,
  % цвет основного блока и текста
  concept color=black!90,text=white]
    node[concept] {VERBS} % первичный/корневой узел
    % 1 уровень
    child[concept color=red!90!black] {
      node[concept] {Simple}
      % 2 уровень
      child [concept color=red!70!black] {
        node[concept] {
        \underline{Present} \\ V/V(es)}
        % 3 уровень
        child [concept] { node[concept] {regular action} }
        child [concept] { node[concept] {work} }
        }
      % 2 уровень
      child [concept color=red!80!black] {
        node[concept] {Past \\ V(ed)/V2}
        % 3 уровень
          child [concept]{
            node [concept] {action in the past}
          }
          child [concept]{ node [concept] {workED}}
        }
    };
\end{tikzpicture} % конец блока TikZ
\end{document} % конец документа

Рекомендуется немного поэкспериментировать с уровнями вложенности, дабы понять их. Также отметим, что:

  • child описывает характеристики узла, содержит узлы (кроме первичного)
  • concept проводит линию, соединяющую элементы
  • node представляет собой узел (элемент)

Полный вариант данной карты можно забрать отсюда. Разумеется, при должном умении есть шанс сделать куда более красивые и функциональные карты: добавить фон, тень, заметки и прочая-прочая.

Деревья

Вряд ли такой структуре как дерево можно дать много определений. Дерево представляет собой иерархическую структуру связанных друг с другом элементов — узлов, верхний из которых является корневым. От верхнего уровня к другим вершинам проходят рёбра. Вершины, не имеющие рёбер, называются листьями.

Впрочем, зачем долго описывать теорию, когда при помощи рисунка можно быстро и наглядно отобразить само дерево? Вот оно:

LaTeX Ruby Classes

Начнём с построения элементов одного уровня, далее будем наблюдать как представленное дерево «разрастается». В то же время слишком глубоких уровней здесь не представлено (безусловно, таковые могут наличествовать, если они нужны).

\usetikzlibrary{trees} % только деревья, библиотека mindmap не требуется
% установим границы полей, дабы рисунок вместился целиком
\usepackage[left=2cm,right=2cm,
    top=2cm,bottom=2cm,bindingoffset=0cm]{geometry}

\begin{document}
\tikz % блок tikz
  \node {Object} % корень дерева
    child { node {Nil Class}} % первый уровень
    child { node {True Class}}
    child { node {False Class}}
    child { node {Numeric}}
    child { node {Time}}
    child { node {Date}}
;
\end{document} % end document

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

Перед началом блока tikz допишем:

% Стили для уровней
\tikzstyle{level 1}=[level distance=5.5cm, sibling distance=2.5cm]
\tikzstyle{level 2}=[level distance=3.5cm, sibling distance=2cm]

Здесь level distance позволит регулировать длину рёбер, а sibling distance распределить ветки уровней так, чтобы они не соприкасались друг с другом. Расстояние в каждом случае подбирается в соответствии с вашими эстетическими предпочтениями.

Теперь можно привести полное содержание файла:

\documentclass[a4paper, landscape]{article}
\usepackage[russian]{babel}
\usepackage[utf8]{inputenc} % UTF-8
\usepackage{tikz}
\usetikzlibrary{trees}
\usepackage{verbatim}
\usepackage[left=2cm,right=2cm,
    top=2cm,bottom=2cm,bindingoffset=0cm]{geometry}

\begin{document}
\pagestyle{empty}

% Set style of the trees
\tikzstyle{level 1}=[level distance=5.5cm, sibling distance=2.5cm]
\tikzstyle{level 2}=[level distance=2.5cm, sibling distance=2cm]

\tikz
  \node {Object}
    child { node {Nil Class}}
    child { node {True Class}}
    child { node {False Class}}
    child { node {Numeric}
      child { node {Integer}
        child { node {Fixnum}}
        child { node {Bignum}}
      }
      child { node {Float}}
      child { node {Complex}}
    }
    child { node {Time}}
    child { node {Date}}
    child { node {String}}
    child { node {Range}}
    child { node {Struct}
      child { node {Struct::Tms}}
    }
    child { node {Array}}
    child { node {Hash}}
;
\end{document} % end document

Дальше интереснее: плавно переходим к цепочкам.

Цепочки

Такое название дано исходя из главной особенности структуры в LaTeX — цепочка, chain. В реальности эта модель скорее представляет собой граф (совокупность вершин и рёбер, нелинейная многосвязная структура с произвольным количеством элементов).

Хотя наш граф будет совсем не сложен, тем не менее, потребуется подключить множество библиотек TikZ, которые могут сослужить неплохую службу при составлении различных блоков.

Указывать цвет также станем немного иначе: сначала зададим определённую гамму цветов в заголовке документа, а затем будем использовать их. Разговор о цвете однажды уже заходил. Подробности иметюся в заметке о навигации по документу.

\documentclass[a4paper]{article}
\usepackage[russian]{babel}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
% библиотеки
\usetikzlibrary{%
  arrows, % стрелки
  shapes.misc, % фигуры
  chains, % цепочки
  positioning, % позиционирование элементов
  scopes, % создание дополнительных веток
  shadows % тени
}
% указание цветов
\definecolor{Gray}{RGB}{102,102,102}
\definecolor{LightGray}{RGB}{178,178,178}
\definecolor{Red}{RGB}{204,0,0}
\definecolor{Pink}{RGB}{255,102,102}

Что можно разукрасить:

  • draw цвет границы
  • top color верхний цвет
  • bottom color нижний цвет
  • color цвет текста

Как можно позиционировать элементы:

  • riglt/left справа или слева от элемента
  • below right/above right ниже/выше справа от элемента
  • xshift/yshift=5mm сдвиг по оси X/Y

Что должно получиться в первом шаге:

Chain First Step
\begin{document}
% установки для элементов
\tikzset{
nonterminal/.style={
    rectangle, % обычный прямоугольник
    % размер блока
    minimum size=6mm,
    very thick, % двойная линия
    draw=Gray, % указываем заданный ранее цвет
    % цвета узлов
    top color=white,
    bottom color=LightGray,
    % шрифт
    font=\itshape
  },
terminal/.style={
    rounded rectangle, % прямоугольник со скруглёнными углами
    drop shadow={opacity=0.35}, % тень от узлов
    minimum size=6mm, % размер узла
    very thick, % двойная линия
    draw=black!50, % цвет обводки
    top color=white,bottom color=black!20, % цвета градиента
    font=\ttfamily} % шрифт
}
% начало блока
\begin{tikzpicture}[node distance=5mm and 5mm] % дистанция между узлами
  % используем позиционирование (right/left/above right/above left=of something)
  \node (dot)[terminal]{.};
  \node (digit) [terminal, right=of dot, yshift=5mm] {digit};
  \node (root)[nonterminal, bottom color=Pink, right=of digit] {root};
  \node (name) [terminal, below right=of dot] {name};
  \node (name2) [terminal, below right=of name, color=Pink] {name2};
\end{tikzpicture} % конец блока
\end{document}

Если всё получилось, можно переходить к следующему шагу: визуальному связыванию узлов. Свяжем их в ранее упомянутую цепочку: chain. Для этого зададим один параметр для стиля узлов и «начнём» цепочку указанием start chain.

% ...
\tikzset{
    every node/.style={on chain},
% ...
    \begin{tikzpicture}[start chain]

В примере ниже нужно будет вручную проводить связующие стрелки между узлами. Их расположение относительно друг друга гибко регулируется. На выходе получится следующее:

On Chain
\begin{tikzpicture}[start chain, node distance=5mm and 5mm] % начало цепочки
  \node (dot)[terminal]{.};
  \node (digit) [terminal, right=of dot, yshift=5mm] {digit};
  \node
  (root)[nonterminal, minimum size=10mm, bottom color=Pink, right=of digit] {root};
  % связь узла root к узлу name
  \node (name) [terminal, join=with root, below right=of dot] {name};
  \node (name2) [terminal, below right=of name, color=Pink] {name2};
    % ответвление от name2
    \begin{scope}[start branch=plus]
      \node (plus)[terminal, on chain=going above right] {+};
      \node (plus2)[terminal, on chain=going below right] {++};
     \end{scope}
     % ответвление от name2
     \begin{scope}[start branch=minus]
       \node (minus) [terminal, on chain=going below left] {-};
       \node (minus2) [terminal, on chain=going below right] {--};
     \end{scope}
\end{tikzpicture}

Также можно автоматически соединить все узлы от первого к последнему. При этом ответвления (branch) будут соединены со своим главным узлом.

every node/.style={on chain, join}, % соединить все узлы
every join/.style={-}, % линии без стрелок
% every join/.style={->}, % или со стрелками
"LaTeX chains"

Углубляться дальше, пожалуй, не станем. С помощью описанных сегодня конструкций вполне неплохо можно жить. Тем, кому этих незамысловатых способов структурирования информации не хватает или же перед кем стоят куда более серьёзные задачи настоятельно рекомендуется обратиться к документации по TikZ, где полностью разъяснены те аспекты, что были рассмотрены сегодня, и многое сверх того. Документация добротная, всеобъемлющая, её хватит даже самому искушённому «графоману».