相对简单的问题:我想使用宏来定义树的子结构。在下面的例子中,我想定义一些子节点(左和右),以便在树中使用多次。
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\newcommand{\leftchildren}{%
child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
}%
\newcommand{\rightchildren}{%
child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
}%
\node[circle,draw] (root) {} \leftchildren \rightchildren;
\end{tikzpicture}
\end{document}
问题是
如果没有标签
(root)
它甚至无法编译(为什么?)宏不在同一级别展开:右子项成为左子项的子项
使用更多宏或嵌套它们会使情况变得更糟。
这是我想要做的事情的一个非常简化的版本。我经常希望能够手动添加其他子项(不使用宏)。我还希望能够将整个子树定义为宏,例如将长链定义为宏。
我认为宏的扩展存在问题,但我自己无法解决。请帮忙。
干杯,奥利弗
答案1
这类似于
您需要预先扩展宏,以便 tikz 解析器可以看到它们:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\node[circle,draw] (root) {} child{node[circle,draw] {l}} child{node[circle,draw] {l}} child{node[circle,draw] {r}} child{node[circle,draw] {r}};
\end{tikzpicture}
aaaaaaaaaaaaaaaaa
\begin{tikzpicture}
\newcommand{\leftchildren}{%
child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
}%
\newcommand{\rightchildren}{%
child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
}%
\node[circle,draw] (root) {} \leftchildren \rightchildren;
\end{tikzpicture}
bbbbbbbbbbbbbbbbbbbbbbbbbbbb
\makeatletter
\let\mypgfutil@ifnch\pgfutil@ifnch
\def\pgfutil@ifnch{%
\let\x@next\@empty
\ifx\pgfutil@let@token\leftchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\ifx\pgfutil@let@token\rightchildren\let\pgfutil@let@token c\let\x@next\expandafter\fi
\x@next\mypgfutil@ifnch}
\makeatother
\newcommand{\leftchildren}{%
child{node[circle,draw] {l}} child{node[circle,draw] {l}} %
}%
\newcommand{\rightchildren}{%
child{node[circle,draw] {r}} child{node[circle,draw] {r}} %
}%
\begin{tikzpicture}
\node[circle,draw] (root) {} \leftchildren \rightchildren;
\end{tikzpicture}
\end{document}
答案2
c
大卫·卡莱尔大师的方法要求始终保持性格。以下是我有时使用的方法。
\documentclass{article}
\usepackage{tikz}
\makeatletter
\newcommand*\tikzcommands{%
% Collect your tikz commands here, otherwise they will be expanded
% prematurely:
\do\begin\do\end\do\coordinate\do\path\do\draw\do\node
}
\def\xtikzpicture{\@ifnextchar'{\@firstoftwo{\xtikz@picture{00}}}%
{\xtikz@picture{01}}}
\def\xtikz@picture#1#2\end#3{%
\def\reserved@a{#3}\def\reserved@b{xtikzpicture}%
\ifx\reserved@a\reserved@b
\def\endxtikzpicture{}%
\end{xtikzpicture}%
\else
\@latexerr{Environment 'xtikzpicture' badly ended}\@ehd
\fi
\let\this@relax\relax
\def\reserved@a##1\this@relax{}%
\if#1\expandafter\reserved@a\fi
\begingroup
\def\do##1{\let##1\relax}\tikzcommands
\protected@edef\x{\endgroup
\begin{tikzpicture}#2\end{tikzpicture}%
}\x
\this@relax
}
\makeatother
\def\leftchildren{%
child{node[circle,draw] {left}}
child{node[circle,draw] {left}}
}
\def\rightchildren{%
child{node[circle,draw] {\textcolor{blue}{right}}}
child{node[circle,draw] {\textcolor{blue}{right}}}
}
\begin{document}
\begin{xtikzpicture}' % ignored
xx
\end{xtikzpicture}
\begin{xtikzpicture}[level distance=10mm,
every node/.style={fill=red!40,circle,inner sep=1pt}]
% Maybe someone can tell me why the circle on 'root' has no effect:
\node {root} [grow'=up,circle,draw]
\leftchildren \rightchildren
child {node {parent}
child {node {child}}
child {node {child}}
};
\end{xtikzpicture}
\end{document}
答案3
使用forest
,您可以轻松指定复杂的子树,以不同的方式格式化它们,并在树中混合显式和自动节点创建。而且您可以非常简洁地完成所有这些操作,而无需担心扩展问题。(至少,通常不需要。)
例如:
\documentclass[tikz,border=5pt,multi]{standalone}
\usepackage{forest}
\begin{document}
\forestset{
my circle/.style={circle, draw},
my node/.style={draw},
left children/.style={
repeat=2{prepend={[l, my circle]}}
},
right children/.style={
repeat=2{append={[r, my circle]}}
},
complex children/.style={
before typesetting nodes={for descendants={my node}},
append={[+1, left children, delay={for children={right children}}, before typesetting nodes={for tree={blue, edge={blue}}}, insert after={[+2, repeat=3{prepend={[p, for tree={green, edge={green}}[p]]}, append={[a, for tree={red, edge={red}}]}}]}]}
}
}
\begin{forest}
[, my circle, left children, right children
[, my circle, complex children]
]
\end{forest}
\end{document}
该样式my circle
只是将节点形状设置为圆形并绘制它。
样式left children
并right children
相对于当前节点使用该my circle
样式创建 2 个左子节点和 2 个右子节点。
该样式complex children
会创建一个由左侧 ( +1
) 和右侧 ( +2
) 组成的子树。默认情况下,此子树中的所有节点都使用 样式,my node
该样式在默认的矩形节点形状周围绘制一个框。左侧为蓝色,根节点使用该my node
样式,但其子节点使用该my circle
样式,因为它们是使用left children
和创建right children
的。右侧最初没有颜色,但此侧的子节点有颜色。左侧的 3 个子节点为绿色,它们的子节点也是绿色。右侧的 3 个子节点为红色。依此类推。
显然,您可以根据需要定义更简单或更复杂的结构和样式。
答案4
您还可以使用以下命令强制扩展宏\edef
:
\edef\tmp{\leftchildren \rightchildren}
\node[circle,draw] (root) {} \tmp;