由于我不精通 Ti钾z 尽管我付出了努力,但我还是没有找到合适的包裹,我想就以下问题寻求建议或者解决方案。
目的是复制以下列表,该列表以某种方式与具有垂直传播的树形图混合。我只需要2 家分店,但我添加了第三个分支以使其更加清晰。
由于有些输入条目很长,最好进行左对齐。图中所示的尺寸可以设置不同,除非它们可实现。
很明显,这种设计不适合分支众多的情况,因为它必须同时满足树形图和列表的功能。因此,对于具有单一深度的可读且全面的结构,最多可能只有 3 个分支(以防其他人使用这种设计)。
在这里我补充一点不是最小工作示例使用逐项列举,但希望它可以在某种程度上被视为一个起点。
\documentclass{article}
\newlength{\BrVert}
\setlength{\BrVert}{1.3\baselineskip}
\newlength{\ItemSep}
\setlength{\ItemSep}{0.5\baselineskip}
\usepackage{enumitem}
\setlist{nosep, label = $\longrightarrow$, leftmargin = 2cm,
topsep = \BrVert, itemsep = \ItemSep}
\begin{document}
\underline{Main text}
\begin{itemize}
\item Rome
\item Paris
\item Madrid
\end{itemize}
\begin{itemize}
\item Mercedes
\item Renault
\item Volvo
\end{itemize}
\begin{itemize}
\item apple
\item pear
\item orange
\end{itemize}
\end{document}
对于“如何做”没有特别的要求。
答案1
编辑请参阅下面的版本,其中考虑了较长的节点文本。
另一种forest
解决方案是使用forest
的参数处理器,从而避免手动绘制边。根节点的子节点没有边。相反,我们使用自定义edge path
的树的叶子,将它们连接到其祖父母(即根)边界上的某个点。这些路径被一个因子取代,该因子取决于其不可见的父节点的子节点数,即其父节点是第一个、第二个还是第三个子节点。您可以使用更多或更少的分支。也就是说,样式允许这样做。这是否有意义是另一个问题。
我们定义了两种forest
风格。
\forestset{%
folders descending
folders descending
在树上施加所需的结构。
folders descending/.style={%
for tree={
folder,
grow'=0,
},
这将应用库folder
中的样式edges
(例如Sandy G 的回答并设置生长方向。这实际上是向东,因为我们不会长太多。我们想要的不是树向下生长,而是树枝向下生长。告诉树横向生长可确保树枝向下(或向上,取决于我们是否使用素数)。
for children={
l sep'+=5pt,
coordinate,
no edge,
},
我们增加根节点的子节点之间的距离,将其边缘分割并使其成为坐标。这些是我们的隐形节点。它们只是作为支撑树结构的支架。
for leaves={
edge path'/.process={ O+nO+nw2+Pw {!r.n children} {!u.n} {(##1-##2)*5} {(!uu.south west) ++(##1 pt,0pt) |- (.child anchor) } },
这会改变叶子边缘的绘制方式。通常,边缘绘制在(!u.parent anchor)
(父节点的父锚点)和 ((.child anchor)
当前节点的子锚点)之间。在这种情况下,我们使用!uu
而不是!u
从祖父节点而不是父节点绘制。!uu
指示forest
从当前节点的父节点的父节点开始,当前节点是树的根节点。
此外,我们不使用父锚点来绘制边缘。相反,我们从锚点开始,然后向右south west
移动或更多,然后再开始绘制。这就是正在做的事情。这里的技巧是,这是一个计算维度,它取决于当前节点与其兄弟节点的关系。0pt
++(##1 pt,0pt)
##1
O+nO+nw2+Pw {!r.n children} {!u.n} {(##1-##2)*5} {(!uu.south west) ++(##1 pt,0pt) |- (.child anchor) }
看起来很复杂,但实际上是实现这一点的相对简单的指令。
我们O+nO+nw2+Pw
从左到右阅读。这是对forest
参数处理器的指令。它的工作是描述后面的参数并告诉forest
如何处理它们。
O+nO+n
O
是一个forest
选项。O+n
表示forest
应被视为数值表达式的选项。因此,O+nO+n
告诉我们前两个参数是forest
选项,应被视为数值表达式。前两个参数是什么?
{!r.n children} {!u.n}
第一个函数检索根节点的子节点数。!r
表示树的根节点,n children
表示其子节点数。在我们的树中,这将返回3
。第二个函数是当前节点父节点的子节点数,n
。所有子节点相对于其兄弟节点都有一个编号。这里,有 3 个子节点,因此它们的编号为1
、2
和3
。
w2+P
这意味着forest
下一个参数应该被理解为前两个()的函数w2
,然后应该由pgfmath
(+P
)进行解析。
{(##1-##2)*5}
因此,这意味着从第一个参数中取出第二个参数并乘以 5。也就是说,从根节点的子节点数量中取出父节点的子节点数量并乘以 5。这将得出(大约)10
、5
和0
。
最后,
w
告诉forest
最后一个参数应该被理解为迄今为止结果的函数。因此(大约)10
,5
并且0
将被插入到
{(!uu.south west) ++(##1 pt,0pt) |- (.child anchor) }
因此,从根的西南角开始的位移将根据分支以我们想要的方式变化。剩下的就是指定我们选择的箭头尖端到边缘的位置。
edge+={-Stealth},
},
},
lined root
lined root
处理强调其根源。
lined root/.style={%
inner xsep=0pt,
outer xsep=0pt,
inner ysep=1pt,
tikz+={\draw (.south west) -- (.south east);},
},
}
这实际上是纯 Ti钾如果希望在其他类型的s中使用相同的风格,则可以在 中指定 Z 和\tikzset
而不是。\forestset
tikzpicture
应用这些样式将产生以下输出,
完整代码
\documentclass[tikz,border=10pt]{standalone}
% ateb: https://tex.stackexchange.com/a/700537/
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta}
\forestset{%
folders descending/.style={%
for tree={
folder,
grow'=0,
},
for children={
l sep'+=5pt,
coordinate,
no edge,
},
for leaves={
edge path'/.process={ O+nO+nw2+Pw {!r.n children} {!u.n} {(##1-##2)*5} {(!uu.south west) ++(##1 pt,0pt) |- (.child anchor) } },
edge+={-Stealth},
},
},
lined root/.style={%
inner xsep=0pt,
outer xsep=0pt,
inner ysep=1pt,
tikz+={\draw (.south west) -- (.south east);},
},
}
\begin{document}
\begin{forest}
lined root,
folders descending,
[Main text
[
[Rome]
[Paris]
[Madrid]
]
[
[Mercedes]
[Renault]east
[Volvo]
]
[
[apple]
[pear]
[orange]
]
]
\end{forest}
\end{document}
更长的节点文本
考虑到问题的细节,上述解决方案是有问题的。特别是,如果节点的文本内容超出了文本块的剩余宽度,它将产生糟糕的结果。
节点可以很容易地变成多行,并且可以轻松地设置为自动换行以适应特定的宽度。但是,在这种情况下,箭头仍然会指向west
子节点的锚点。在我看来,这看起来相当奇怪。
当然,节点内容越长,奇怪之处就越明显。
这里没有真正适合此目的的现成锚点。我们想要的是位于文本第一行左中部的锚点。(至少,这是我想要的。)此外,如果我们能够forest
适当调整叶节点的宽度,那就太好了。
以下解决方案并不理想。特别是,我不确定为什么我需要将宽度调整为4pt
。我期望2.5pt
或者,也许,2.5pt
加上线宽,或者,甚至是线宽的两倍,但4pt
似乎完全超出了范围。
这是试图在l
不打包整个树的情况下获取数据,这可能是问题的一部分。打包并重新打包整个数据可能会有所帮助,但这也会减慢速度,特别是如果您使用许多或复杂的此类树。
使用绘制的节点进行测试showframe
:
我建议folders descending
在宽度不是问题的地方使用,并且wide folders descending
只在必要时使用,部分原因是后者涉及更多的阴谋,部分原因是由于重新打包和重新排版节点,它会变得更慢。
\documentclass[a4paper]{article}
% ateb: https://tex.stackexchange.com/a/700537/
%\usepackage[showframe]{geometry}
\usepackage{geometry}
\usepackage[edges]{forest}
\usetikzlibrary{arrows.meta}
\forestset{%
common folders descending/.style={%
for tree={
folder,
grow'=0,
},
for children={
l sep'+=7.5pt,
coordinate,
no edge,
},
for leaves={
edge+={-Stealth,shorten >=2.5pt},
},
},
folders descending/.style={%
common folders descending,
for leaves={
edge path'/.process={ O+nO+nw2+Pw {!r.n children} {!u.n} {(##1-##2)*5} {(!uu.south west) ++(##1 pt,0pt) |- (.child anchor) } },
},
},
wide folders descending/.style={%
common folders descending,
for leaves={%
child anchor=north west,
edge path'/.process={ O+nO+nw2+Pw {!r.n children} {!u.n} {(##1-##2)*5} {(!uu.south west) ++(##1 pt,0pt) |- ([yshift=-0.5\baselineskip].child anchor) } },
},
before packing={%
for first leaf={%
!u.pack',
tempdima'=\textwidth,
tempdima'-/.option=l,
tempdima'-=4pt,
},
for leaves={%
inner sep=0pt,
text width/.register=tempdima,
content+=\strut,
typeset node,
},
},
},
lined root/.style={%
inner xsep=0pt,
outer xsep=0pt,
inner ysep=1pt,
tikz+={\draw (.south west) -- (.south east);},
},
}
\begin{document}
\noindent
\begin{forest}
lined root,
wide folders descending,
%for tree={draw},% used for the test
[Main text
[
[Rome]
[Paris]
[Madrid]
]
[
[Mercedes]
[Renault]
[Volvo]
]
[
[apple]
[pear]
[orange]
]
[
[% Translation at http://welshnurseryrhymes.wales/Gartref?cerdd=15
{Oes gafr eto? Oes heb ei godro? Gafr wen, wen, wen, ie finwen, finwen, finwen, \dots{} wen-wen-wen.}]
[{Oes gafr eto? Oes heb ei godro? Gafr wyrdd, wyrdd, wyrdd, ie finwyrdd, finwyrdd, finwyrdd, \dots{} wyrdd-wyrdd-wyrdd.}]
]
]
\end{forest}
\end{document}
答案2
forest
这是使用内置样式的可能性folder
。
\documentclass{article}
\usepackage[edges]{forest}
\forestset{root/.style={name=main, inner xsep=0pt, inner ysep=2pt,
before drawing tree={x-=10*n_children, x+=22.5},
for children={coordinate, no edge, before packing={l=-10*n}}}}
\newcount\nch
\begin{document}
\begin{forest}
TeX={\nch=0},
for tree={folder, folder indent=0pt, grow'=0, edge={->},
if level=2{tier=yes}{},
if level=1{TeX={\advance\nch1}}{}
}
[Main text, root
[[Rome][Paris][Madrid]]
[[Mercedes][Renault][Volvo]]
[[apple][pear][orange]]
[[red][green][blue][yellow]]
]
{\foreach \k in {1,...,\nch}{\draw(!\k)|-(main.south east);}}
\end{forest}
\end{document}
答案3
可以使用列表来执行此操作,但我认为使用表格环境会更容易。以下解决方案不是完全自动化的,但很容易适应,我认为可以让您非常轻松地构造新示例。
\documentclass{article}
\usepackage{enumitem}
\usepackage{calc}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{array,tabularx}
\newcounter{titem}
\newlength{\alistoffset}
\setlength{\alistoffset}{4pt}
\newlength{\alistwidth}
\newlength{\alistinitial}
\newlength{\alistheight}
\setlength{\alistheight}{7pt}
\setlength{\alistinitial}{\alistheight+\extrarowheight}
\newcolumntype{A}{@{\hspace{\alistwidth}\stepcounter{titem}\mkitem{\thetitem}}p{2in}}
% alternative if using tabularx
\newcolumntype{B}{@{\hspace{\alistwidth}\stepcounter{titem}\mkitem{\thetitem}}X}
\NewDocumentCommand{\mkitem}{m}{
{\tikz[remember picture]{\node[anchor=center,inner sep=0pt, outer sep=0pt,minimum height=1ex] (#1) {};}}}
\NewDocumentCommand{\alistpreamble}{m}{
\setlength{\alistwidth}{\widthof{#1}}
\mkitem{begin}#1\mkitem{end}
\vspace*{\alistheight}\par
}
\begin{document}
\alistpreamble{This is some text.}
% adjust item separation with \extrarowheight
%\setlength{\extrarowheight}{6pt}
\begin{tabularx}{\textwidth}[t]{A}
Rome is the capital city of the Italian republic.\\
Paris is the capital city of the French republic.\\
Madrid\\
Mercedes\\
Renault\\
Volvo\\
apple\\
pear\\
orange
\end{tabularx}
\tikz[remember picture,overlay,]{
\draw ($(begin)+(0,-\alistinitial)$) -- ($(end)+(-6pt,-\alistinitial)$);
\foreach \x in {1,...,3} {\draw[->] ($(begin)+(.5\alistwidth,-\alistheight)$) |- ($(\x)+(-\alistoffset,0)$);}
\foreach \x in {4,...,6} {\draw[->] ($(begin)+(.25\alistwidth,-\alistheight)$) |- ($(\x)+(-\alistoffset,0)$);}
\foreach \x in {7,...,9} {\draw[->] ($(begin)+(0\alistwidth,-\alistheight)$) |- ($(\x)+(-\alistoffset,0)$);}}
\end{document}
答案4
更新
有一些虚假代码已被删除。此外,有人指出了对组中的第一个项目进行特殊处理的可能性。已完成。
我来晚了一点。我一直在和 Ti 鬼混钾最近有 Z 链,所以我认为这是可能的。长节点文本不会造成问题。
\documentclass{article}
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz}
\usetikzlibrary{positioning,chains}
\newcounter{gennum}
\newcounter{itemnum}
\newcounter{ingennum}
\newtoks\gentox
%% |=====8><-----| %%
\NewDocumentCommand{\levels}{s >{\SplitList{;}}m }{% splits the list
\ProcessList{#2}{\fooaux}%
}
\NewDocumentCommand{\fooaux}{m} {% manipulates the entries
\stepcounter{itemnum}%
\stepcounter{ingennum}%
\node[on chain,text width=3in,name=L\thegennum-\theitemnum]%change <text width> to suit
{% content
\ifnum\theingennum=1 \bfseries\color{red}\fi %% omit/alter to suit
\strut#1\strut
};%
\draw[<-] (L\thegennum-\theitemnum.west) --
++(-8pt*\thegennum,0)coordinate(C\thegennum-\theitemnum);% change <8pt> to suit
}
\NewDocumentEnvironment{mkgenlist}{m}{% #1=topic text
\setcounter{itemnum}{0}%
\setcounter{gennum}{0}%
\begin{tikzpicture}[outer sep=0pt,start chain=going {below=of \tikzchainprevious.south west},
every on chain/.style={anchor=north west},node distance=-3pt]% change node distance to suit
}{%
\coordinate (cbbnw) at (current bounding box.north west);
\the\gentox
\node[above=0pt of cbbnw,anchor=south west,inner xsep=0pt,name=T] {#1};
\draw (cbbnw) -- (T.south east);
\end{tikzpicture}
}
\NewDocumentCommand{\gen}{m}{% a ;-separated list as argument
\stepcounter{gennum}
\setcounter{ingennum}{0}
\levels{#1}
\edef\foo{\gentox={\the\gentox \noexpand\draw (C\thegennum-\theitemnum) --
(C\thegennum-\theitemnum |- cbbnw);}}\foo
}
\begin{document}
\thispagestyle{empty}
\begin{mkgenlist}{An assortment of words\dots}
\gen{Rome;
Paris;
Madrid}
\gen{Mercedes;
Renault;
Volvo}
\gen{apple;
pear;
orange;
This is a bunch of bla bla bla to see what is happening with long text.}
\gen{acorn;squash;alfalfa;sprouts;almond;bacon;bagel;baked~Alaska;fennel;fig;fillet}
\end{mkgenlist}
\end{document}
新版本
在相当另一个应用程序,一些附加功能被证明是有用的。请注意使用keyval.sty
以使定制更容易。
\documentclass{article}
%% +first item of each group gets special treatment; keyval; first line; number items
\usepackage[papersize={5.5in,8.5in},margin=0.6in]{geometry}
\usepackage{tikz,keyval}
\usetikzlibrary{positioning,chains}
\newcounter{gennum}
\newcounter{itemnum}
\newcounter{ingennum}
\newlength{\arrowln}
\newlength{\gentextwd}
\newlength{\nodedist}
\newtoks\gentox
\newif\iffirstline % first line of group treat differently
\newif\ifnumline % the arrows carry the number of the item
\setlength{\arrowln}{8pt}% length of arrow
\setlength{\gentextwd}{3in} % text width of item
\setlength{\nodedist}{0pt}% vertical distance between nodes
\makeatletter
\define@key{vtree}{firstline}[true]{\csname firstline#1\endcsname}
\define@key{vtree}{arrowln}{\setlength{\arrowln}{#1}}
\define@key{vtree}{gentextwd}{\setlength{\gentextwd}{#1}}
\define@key{vtree}{nodedist}{\setlength{\nodedist}{#1}}
\define@key{vtree}{numline}[true]{\csname numline#1\endcsname}
\makeatother
%% |=====8><-----| %%
\NewDocumentCommand{\levels}{s >{\SplitList{;}}m }{% splits the list
\ProcessList{#2}{\fooaux}%
}
\NewDocumentCommand{\fooaux}{m} {% manipulates the entries
\stepcounter{itemnum}%
\stepcounter{ingennum}%
\node[on chain,text width=\gentextwd,name=L\thegennum-\theitemnum]%change <text width> to suit
{% content
\iffirstline\ifnum\theingennum=1 \bfseries\color{red}\fi\fi %% omit/alter to suit
\strut#1\strut
};%
\ifnumline
\draw[<-] (L\thegennum-\theitemnum.west)
--node[font=\tiny,fill=white,inner sep=1pt]{\theitemnum.\theingennum}
++(-\arrowln*\thegennum,0)coordinate(C\thegennum-\theitemnum);
\else
\draw[<-] (L\thegennum-\theitemnum.west)
-- ++(-\arrowln*\thegennum,0)coordinate(C\thegennum-\theitemnum);
\fi
}
\NewDocumentEnvironment{mkgenlist}{s O{} m}{% #1=topic text
\setkeys{vtree}{#2}
\setcounter{itemnum}{0}%
\setcounter{gennum}{0}%
\begin{tikzpicture}[outer sep=0pt,start chain=going {below=of \tikzchainprevious.south west},
every on chain/.style={anchor=north west},node distance=\nodedist]%
}{%
\coordinate (cbbnw) at (current bounding box.north west);
\the\gentox
\node[above=0pt of cbbnw,anchor=south west,inner xsep=0pt,name=T] {#3\kern3pt};
\draw (cbbnw) -- (T.south east);
\end{tikzpicture}
}
\NewDocumentCommand{\gen}{m}{% a ;-separated list as argument
\stepcounter{gennum}
\setcounter{ingennum}{0}
\levels{#1}
\edef\foo{\gentox={\the\gentox \noexpand\draw (C\thegennum-\theitemnum) --
(C\thegennum-\theitemnum |- cbbnw);}}\foo
}
\begin{document}
\thispagestyle{empty}
\begin{mkgenlist}[arrowln=16pt,firstline,numline,gentextwd=2in,nodedist=-3pt]{An assortment of words\dots}
\gen{Rome;
Paris;
Madrid}
\gen{Mercedes;
Renault;
Volvo}
\gen{apple;
pear;
orange;
This is a bunch of bla bla bla to see what is happening with long text.}
\gen{acorn;squash;alfalfa;sprouts;almond;bacon;bagel;baked~Alaska;fennel;fig;fillet}
\end{mkgenlist}
\end{document}