更长的节点文本

更长的节点文本

由于我不精通 Tiz 尽管我付出了努力,但我还是没有找到合适的包裹,我想就以下问题寻求建议或者解决方案。

目的是复制以下列表,该列表以某种方式与具有垂直传播的树形图混合。我只需要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 个子节点,因此它们的编号为123

w2+P

这意味着forest下一个参数应该被理解为前两个()的函数w2,然后应该由pgfmath+P)进行解析。

{(##1-##2)*5}

因此,这意味着从第一个参数中取出第二个参数并乘以 5。也就是说,从根节点的子节点数量中取出父节点的子节点数量并乘以 5。这将得出(大约)1050

最后,

w

告诉forest最后一个参数应该被理解为迄今为止结果的函数。因此(大约)105并且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而不是。\forestsettikzpicture

应用这些样式将产生以下输出,

树形列表

完整代码

\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}

带有 keyval 选项的新版本

相关内容