Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0

в 13:59, , рубрики: latex, граф, диаграмма, метки: , ,

Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0

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

Упрощённая нотация графов

Стандартными командами рисования узлов и линий в TikZ являются node и path, но код с ними получается довольно многословным и за забором из команд node можно потерять саму диаграмму. В TikZ 3.0 появилась упрощённая нотация для графов, позаимствованная из известного пакета Graphviz и его языка DOT. В DOT-нотации простейший граф можно записать как последовательность текстовых меток и псевдострелочек, вроде a -> b -> c.

Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0

Начнём с преамбулы:

usepackage{tikz}  
usetikzlibrary{graphs}

И сделаем простенький граф:

  begin{tikzpicture}
  graph {
    Диакритика? -> Да! -> Французский
  };
  end{tikzpicture}

Команда graph в своём аргументе принимает описание графа в DOT-нотации, и мы полагаем, что получим цепочку из трёх вершин. В действительности же не всё так просто: наши метки сбились в кучамалу (пункт 1 на картинке «Цепочка Вершин»)

Позиционировать узлы графа можно вручную, и мы этим займемся в следующей части, но пока попробуем автоматическое позиционирование. Самое простое, что можно сделать, это подсказать TikZ'у в опциях команды graph, куда должен расти граф и куда ветвиться. Давайте растить граф вправо, так чтоб центры узлов располагались на сетке с шагом три сантиметра (пункт 2):

    begin{tikzpicture}
    graph[grow right=3cm] {
        Диакритика? -> Да! -> Французский
    };
    end{tikzpicture}

Можно указать расстояние не между центрами, а между соседними краями узлов (пункт 3):

    begin{tikzpicture}
    graph[grow right sep=2em] {
        Диакритика? -> Да! -> Французский
    };
    end{tikzpicture}

Граф можно растить в любом направлении. Стандартные направления right, left, up, down ортогональны осям координат, но можно растить и под углом (пункт 4):

    begin{tikzpicture}
    graph[chain shift=(-45:1)] {
        Диакритика? -> Да! -> Французский
    };
    end{tikzpicture}
Произвольный текст в метках

Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0

Если в метке есть, например, дефис, или ещё что-нибудь более-менее сложное (математическая формула?), то нас без дополнительных подсказок не поймут, а вот если его закавычить, то всё будет ок:

    begin{tikzpicture}
    graph[grow right sep=1em] {
        Диакритика? -> Много над E:\ `{E}, '{E}, ^{E}, "{E} -> Французский
    };
    end{tikzpicture}

    begin{tikzpicture}
    graph[grow right sep=1em] {
        Диакритика? -> "Много над E:\ `{E}, '{E}, ^{E}, "{E}" -> Французский
    };
    end{tikzpicture}
Ветвление графа

Давайте сделаем нашу схему посложнее и добавим ветвление. В DOT-нотации узлы можно объединить в группу при помощи фигурных скобок и к каждому из узлов группы провести дугу из узла-предка:

    begin{tikzpicture}
    %% Опция nodes определяет параметры всех узлов графа. align=center центрирует текст в узле
    graph[nodes={align=center}, grow down sep, branch right sep] {
        Диакритика? ->
        {
            "Много над E:\ `{E}, '{E}, ^{E}, "{E}" ->  Французский,
            Мало -> "Хоть что-то есть?" -> 
            {
                "c{C} и "{E}" -> Точно не французский? -> 
                { 
                   "Ой$dots$он" -> Французский,
                   Вроде нет -> Албанский
                },
                "Только "{A} и "{O} \ но мноогоо \ сдвооенных" -> Финский
            }
        } 
    };
    end{tikzpicture}

Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0

Как видите, из узлов-вопросов провелись дуги к соответствующим узлам-ответам. За расположение узлов при ветвлении отвечает параметр branch, в нашем случае right sep говорит что ветвление должно идти вправо, с одинаковым расстоянием между слоями. Он может принимать и другие значения, аналогично параметру grow. Кстати, нам понадобилось указать выравнивание текста в узлах, без которого не сработали бы переносы строк в метках

Но у нас, похоже, проблема. Дуга из узла «Ой… он» к выводу «Французский» провелась, но пошла куда-то вверх. Нельзя ли сделать так, чтоб вывод «Французский» был ниже всех предшествующих ему вопросов и ответов? Если наивно поместить вывод «Французский» за всей группой после вопроса «Диакритика?» то дуги проведутся из всех листьев группы:

    begin{tikzpicture}
    %% Добавим стиль рисования всех узлов
    graph[nodes={align=center,rectangle,draw=black}, grow down sep, branch right sep] {
        Диакритика? ->
        {
            "Много над E:\ `{E}, '{E}, ^{E}, "{E}",
            Мало -> "Хоть что-то есть?" -> 
            {
                "c{C} и "{E}" -> Точно не французский? -> 
                { 
                   "Ой$dots$он",
                   Вроде нет -> Албанский
                },
                "Только "{A} и "{O} \ но мноогоо \ сдвооенных" -> Финский
            }
        } -> 
        Французский
    };
    end{tikzpicture}

Диаграммы и графы в LaTeX с использованием PGF/TikZ 3.0
Но можно явно исключить листья из списка концов проводимых дуг, добавив опции not source и not target. Их названия несколько противоречивы: так, чтобы указать, что из узла «Албанский» не должна идти дуга в узел «Французский» надо приписать к узлу «Албанский» опцию [not target]

    begin{tikzpicture}
    graph[nodes={align=center,rectangle,draw=black}, grow down sep, branch right sep] {
        Диакритика? ->
        {
            "Много над E:\ `{E}, '{E}, ^{E}, "{E}",
            Мало -> "Хоть что-то есть?" -> 
            {
                "c{C} и "{E}" -> Точно не французский? -> 
                { 
                   "Ой$dots$он",
                   Вроде нет -> Албанский[not target]
                },
                "Только "{A} и "{O} \ но мноогоо \ сдвооенных" -> Финский[not target]
            }
        } -> 
        Французский
    };
    end{tikzpicture}

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

Ссылки:
[1] Исходный текст диаграмм из статьи и скомпилированный результат
[2] Пакет PGF/TikZ

Автор: dbarashev

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js