Coding a new layout algorithm for tikz's graph library is a daunting task, even in Lua, even as "simple" as the one you want. The reason is the great amount of "boilerplate code" needed.
Instead, it is very easy to "cheat" and use one of the already provided algorithms, but changing one of its parts. In this case, we can take the layered layout
and remove the part which does the node reordering in each layer.
But even this is not so simple, because we don't want to modify any of the lua "system files". We want all our changes to be confined to the document folder.
I've found a way to do it. I do not claim it is the cleanest way (nor even the easiest way perhaps some phases of the algorithm can be changed via pgf keys). But it works (see update 1 for a cleaner and nicer way).
What follows shows how it can be done.
The result
The LaTeX document
\documentclass[tikz,convert,margin=10pt]{standalone}
\usetikzlibrary{graphs,graphdrawing}
%\usegdlibrary{layered} % <--- This line removed
\usegdlibrary{layered-no-reorder} % <--- This one added
\begin{document}
\tikz[rounded corners] \graph [layered layout]
{
{[same layer] \foreach \i in {1, 2, ..., 16} {
pt\i/$P^0_{\i}$,
}};
{[same layer] \foreach \i in {1, 2, ..., 17} {
l\i/$P^1_{\i}$,
}};
\foreach \i [evaluate=\i as \j using int(\i+1)] in {1,2,...,16} {
pt\i -- l\i,
pt\i -- l\j,
};
Q/$P^1 \times P^1$ [gray];
\foreach \i [evaluate=\i using int(2*\i)] in {1,2,...,7} {
l\i -- [gray, edge node = {node [fill=white] {h}}] Q,
};
pt1 -- [gray] Q;
};
\end{document}
The remaining files in the document folder
layered-no-reorder.lua
This one is based in texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/library.lua
. Only comments were removed, and one line changed (marked below):
local layered
-- Load declarations from:
require "pgf.gd.layered"
-- Load algorithms from:
require "pgf.gd.layered.Sugiyama"
require "pgf.gd.layered.cycle_removal"
require "pgf.gd.layered.node_ranking"
require "no_crossing_minimization" -- <-- This one changed
require "pgf.gd.layered.node_positioning"
require "pgf.gd.layered.edge_routing"
no_crossing_minimization.lua
This one is based on texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/crossing_minimization.lua
. All comments were stripped out for brevity. The only interesting change is the marked line, which originally was require "pgf.gd.layered.CrossingMinimizationGansnerKNV1993"
.
local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare
declare {
key = "no crossing minimization",
algorithm = require "noCrossing", -- <--- This one changed
phase = "crossing minimization",
phase_default = true,
summary = [["
Fake phase. Does nothing.
"]],
documentation = [["
For more details, please see
http://tex.stackexchange.com/questions/173540/use-layered-layout-with-user-specified-node-ordering-i-e-with
out-crossing-m
"]]
}
noCrossing.lua
This one is based on texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/layered/CrossingMinimizationGansnerKNV1993.lua
, but heavily stripped down. Only the run()
function remains, and basically does nothing.
local CrossingMinimizationNone = {}
function CrossingMinimizationNone:run()
return self.ranking
end
return CrossingMinimizationNone
Update 1
There is a cleaner way to integrate the new "no reorder" algorithm into the general layered layout
, without replacing the library. This way the author still has control to decide if he wants some graphs using the standard sweep crossing minimization
(which is the default in Tikz) while others use the new no crossing minimization
.
This is how:
- Remove the file
layered-no-reorder.lua
used in previous solution. It is no longer required, since standard layered
library will be used instead.
- Remove the file
no_crossing_minimization.lua
. We will rewrite it (with a different name) in a better way.
- Keep the file
noCrossing.lua
as in the previous solution. This is the file which implements the new "algorigthm" for the reordering phase.
Now, write the following in a file called more-crossing-algorightms.lua
:
local declare = require("pgf.gd.interface.InterfaceToAlgorithms").declare
---
declare {
key = "no crossing minimization",
algorithm = require "noCrossing",
phase = "crossing minimization",
phase_default = false,
summary = [["
Fake phase. Does nothing.
"]],
documentation = [["
For more details, please see http://tex.stackexchange.com/questions/173540/use-layered-layout-with-user-specified-node-ordering-i-e-without-crossing-m
"]]
}
Note the key
property. It is the name of a key which can be used later in the TikZ diagram to select this algorithm. In principle, we could declare more crossing algorithms in this same file, giving a different key to each one. This will allow to select one or other from tikz, using the appropiate key. Note also the phase_default
property, which is set to false
. This means that this algorithm will not be used by default, but only when it is explicitly selected with the key no crossing algorithm
.
Now the main file is:
\documentclass[tikz,convert,margin=10pt]{standalone}
\usetikzlibrary{graphs,graphdrawing}
\usegdlibrary{layered} % <-- Now we do not replace this one
\usegdlibrary{more-crossing-algorithms}% <-- but extend it, loading more algorithms
\begin{document}
\tikz[rounded corners] \graph [layered layout, no crossing minimization]
{
{[same layer] \foreach \i in {1, 2, ..., 16} {
pt\i/$P^0_{\i}$,
}};
{[same layer] \foreach \i in {1, 2, ..., 17} {
l\i/$P^1_{\i}$,
}};
\foreach \i [evaluate=\i as \j using int(\i+1)] in {1,2,...,16} {
pt\i -- l\i,
pt\i -- l\j,
};
Q/$P^1 \times P^1$ [gray];
\foreach \i [evaluate=\i using int(2*\i)] in {1,2,...,7} {
l\i -- [gray, edge node = {node [fill=white] {h}}] Q,
};
pt1 -- [gray] Q;
};
\end{document}
Note the \tikz
line. It has the option no crossing minimization
, which selects the new algorithm. If we omit that option, then the default sweep crossing algorithm
will be selected (because it is marked as the default algorithm in TikZ libraries).
To sum up, all the files required in this new solution are test.tex
(main document), more-crossing-algorithms.lua
and noCrossing.lua
. Standard TikZ libraries are not replaced, but extended.