![自动将图形节点标签放置在节点外部](https://linux22.com/image/464421/%E8%87%AA%E5%8A%A8%E5%B0%86%E5%9B%BE%E5%BD%A2%E8%8A%82%E7%82%B9%E6%A0%87%E7%AD%BE%E6%94%BE%E7%BD%AE%E5%9C%A8%E8%8A%82%E7%82%B9%E5%A4%96%E9%83%A8.png)
我正在使用 TikZ+LuaTeX 图形绘制库,并且很喜欢它。我正在尝试匹配一种将顶点标签绘制在顶点外部的样式。以下是示例:
(从离散数学导论,作者:Edward R. Scheinerman。(C)2012 Cengage Learning)
我以为我会很聪明地将节点标签伪装成图形节点,使其与相应节点的边不可见。但当然,它们与节点的距离与其他节点一样远。在使用图形force
绘制库时,我找不到让特定边自然变短的方法。
因此,我决定将顶点标签的节点也设为不可见,并手动将节点标签放置在每个实际节点与其不可见标签节点之间的线段上。这很有效。
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{graphs,graphdrawing}
\usegdlibrary{force}
\begin{document}
\begin{tikzpicture}
\begin{scope}[
spring layout,
node distance=2cm,
vertex/.style={
draw,circle,minimum size=1ex, inner sep=0pt
}
]
\foreach \i in {1,...,6} {
% The actual nodes
\draw node[vertex] (\i) {}
% vertex label directions as nodes
node (\i-labeldir) {}
(\i) edge[draw=none] (\i-labeldir);
}
% the actual edges
\draw (1) edge (2) edge (3) edge (5) edge (6)
(2) edge (3) edge (4)
(3) edge (6);
\end{scope}
% the actual labels (can't be put in for loop?)
\draw ($(1)!2ex!(1-labeldir)$) node {$1$}
($(2)!2ex!(2-labeldir)$) node {$2$}
($(3)!2ex!(3-labeldir)$) node {$3$}
($(4)!2ex!(4-labeldir)$) node {$4$}
($(5)!2ex!(5-labeldir)$) node {$5$}
($(6)!2ex!(6-labeldir)$) node {$6$}
;
% also: bounding box is too big
\end{tikzpicture}
\end{document}
这很令人满意,但我更喜欢更简洁一些的。例如,
不可见节点使边界框太大。我认为我可以使用
fit
库来解决这个问题。我无法将节点标签放置在
\foreach
循环中。这没有解析:\foreach \i in {1,...,6} { \draw ($(\i)!2ex!(\i-labeldir)$) node {$\i$}; }
但主要的是:真的没有办法将特定边的自然长度设置为与 s 中的其他边不同吗
spring layout
?我尝试调整spring constant
,但这似乎只会产生全局影响。我还尝试了spring electrical layout
,并调整了electrical charge
标签节点的,但这也会影响其他节点的放置。
答案1
我也不喜欢……
放置节点和边时该overlay
选项似乎被忽略。graphdrawing
--[draw=none]
用螺丝钉替换边缘会-!-
破坏整个图表。
该方法通过overlay
绘制整个图但将所有节点保存在宏中并在其周围拟合一个未覆盖的节点来实现,基本上是手动评估边界框。(这忽略了所有边缘,但除非它们只在“真实”节点之间,否则它应该可以工作……)
代码
% !TeX TS-program = lualatex
\documentclass[tikz]{standalone}
\usetikzlibrary{fit, graphs, graphdrawing, quotes}
\usegdlibrary{force}
\makeatletter
\tikzset{
every picture/.append code={\let\tikz@graphs@bbnodes\pgfutil@empty},
every picture/.append style={
execute at end picture={\node[rectangle,path only,inner sep=+0pt,fit/.expanded=\tikz@graphs@bbnodes]{};}},
save this node/.style={append after command=\pgfextra{\xdef\tikz@graphs@bbnodes{\tikz@graphs@bbnodes(\tikzlastnode)}}}}
\makeatother
\begin{document}
\tikz[vertex/.style={draw, circle, minimum size=1ex, inner sep=0pt, save this node}]
\graph[
/tikz/overlay,
spring layout,
node distance=2cm,
typeset =,
edge quotes= {save this node}
]{
\foreach \i in {1,...,6}{[parse/.expanded={% \i in quotes expansion issue
\i[vertex] --[draw=none, "$\i$" near start] \i'[coordinate]}]},
1 -- {2, 3, 5, 6},
2 -- {3, 4},
3 -- 6
};
\end{document}
输出
答案2
我定义了一个命令\selabels
,它接受一个参数(顶点数)并写入您想要的标签。\tikzmath
当然,它使用循环。否则,您的初始代码不会被修改。
评论。我不知道如何修改看不见的边缘的长度。
代码
\documentclass[margin=10pt]{standalone} % {article} %
\usepackage{tikz}
\usetikzlibrary{calc, math, fit}
\usetikzlibrary{graphs, graphdrawing}
\usegdlibrary{force}
\begin{document}
\newcommand{\setlabels}[1]{%
\tikzmath{
integer \i;
coordinate \v;
for \i in {1, ..., #1}{%
\v = (\i-labeldir.center) -(\i.center);
\t{\i} = {atan2(\vy, \vx)};
{
\path (\i.center) ++(\t{\i}:1.5ex) node {\i};
};
};
}
}
\begin{tikzpicture}[every node/.style={scale=.7}]
\begin{scope}[spring layout, node distance=2cm,
vertex/.style={
draw, circle, minimum size=1ex, inner sep=0pt
}]
\foreach \i in {1,...,7} {
\draw[] node[vertex] (\i) {} % actual nodes
node (\i-labeldir) {} % vertex label directions as nodes
(\i) edge[draw=none] (\i-labeldir);
}
% actual edges
\draw
(1) edge (2) edge (3) edge (5)
(2) edge (3) edge (4)
(3) edge (6) edge (7)
(5) edge (7);
\end{scope}
% actual labels
\setlabels{7}
\end{tikzpicture}
\end{document}