编辑

编辑

我正在制作系统发育树森林,使用这个问题和答案作为指导。

我想要一个垂直时间轴,如下图所示,但我有两个相关问题,我不知道如何解决。

  1. 我希望轴出现在树的左侧,偏移特定量,比如说最左侧分支(或叶节点标签;例如本例中的灰狐狸)左侧 1 厘米。好的,现在,我必须通过反复试验找到距离。随着树的大小发生变化(添加或删除节点),轴的位置应相应调整。

  2. 我希望轴的长度能够自动适应树的高度。现在,我手动计算层数并乘以值l set(本例中为 1 厘米)。

这两者都可以通过编程来确定吗?

\documentclass{article}
\usepackage{forest}
\usetikzlibrary{positioning, backgrounds}
\tikzset{
    timeline/.style={align=right, text width=2cm},
     no edge from this parent/.style={
        every child/.append style={
        edge from parent/.style={draw=none}}},
}
\forestset{
    every leaf node/.style={
        if n children=0{\raggedright #1}{}
    },
    every tree node/.style={
        if n children=0{}{#1}
    },
    mytree/.style={
        for tree={
            edge path={
            \noexpand\path [draw, ultra thick, \forestoption{edge}] (!u.parent anchor) -| (.child anchor)\forestoption{edge label};
            },
            every tree node={draw=none,inner sep=0, outer sep=0, minimum size=0},
            every leaf node/.style={align=right},
            grow'=north,
            parent anchor=north, 
            child anchor=south,
            anchor=base,
            l sep=1cm,
            s sep=3mm,
            draw=none,
                if n children=0{tier=word, align=center, base=bottom}{}
        }
    }
}

\begin{document}
\begin{forest} mytree
    [, name=lvl0
        [,name=lvl1
            [,name=lvl2
                [gray fox]
                [island fox]
            ]
            [
                [,name=lvl3
                    [black\\bear]
                    [giant\\panda] 
                ]
                [
                    [northern\\elephant\\seal]
                    [walrus] 
                ] 
            ] 
        ]
    ]
    %
    \coordinate (tml) at (-6.5,0);
    \begin{scope}[on background layer]
        \draw (-5.3,0) -- (-5.3,4) node [above] {\textsc{mya}};
        \foreach \x/\age/\len in {1/10/2, 2/7.4/4, 3/4/4}
            {
            \node[timeline] (age\x) at (lvl\x -| tml) {\age};
            \draw[gray, thick, dotted] (age\x) -- (lvl\x);
        }
    \end{scope}
\end{forest}
\end{document}

在此处输入图片描述

答案1

像这样吗?

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\usetikzlibrary{backgrounds}
\forestset{
  declare dimen register={timeline offset},
  timeline offset'=10mm,
  declare toks register={timeline target},
  timeline target=,
  declare boolean={tree node}{0},
  mytree/.style={
    for tree={
      edge+={ultra thick},
      edge path'={
        (!u.parent anchor) -| (.child anchor)
      },
      grow'=north,
      parent anchor=children,
      child anchor=parent,
      anchor=base,
      l sep=1cm,
      s sep=3mm,
      if n children=0{tier=word, align=center, base=bottom, not tree node}{coordinate, tree node}
    }
  },
  timeline/.style={
    before drawing tree={
      timeline target/.option=name,
      tempdima/.option=y,
      for tree={
        if={>OR>{y}{tempdima}}{timeline target/.option=name}{},
      }
    },
    tikz+={
      \begin{scope}[on background layer]
        \draw ([xshift=-\foresteregister{timeline offset}]current bounding box.west |- .parent anchor) coordinate (timeline base) -- (\foresteregister{timeline target}.child anchor -| timeline base) node [above] {\textsc{mya}};
      \end{scope}
    },
  },
}

\begin{document}
\begin{forest}
  mytree,
  timeline
    [, name=lvl0
        [,name=lvl1
            [,name=lvl2
                [gray fox]
                [island fox]
            ]
            [
                [,name=lvl3
                    [black\\bear]
                    [giant\\panda]
                ]
                [
                    [northern\\elephant\\seal]
                    [walrus]
                ]
            ]
        ]
    ]
    \begin{scope}[on background layer]
        \foreach \x/\age/\len in {1/10/2, 2/7.4/4, 3/4/4}
            {
            \node [anchor=east] (age\x) at (lvl\x -| timeline base) {\age};
            \draw [gray, thick, dotted] (age\x) -- (lvl\x);
        }
    \end{scope}
\end{forest}
\end{document}

自动安排时间

编辑

这是一个略有不同的版本,它允许您说出age=<value>树中的节点,然后自动完成其余操作。至少,理论上是这样的。

\documentclass[border=10pt,multi,tikz]{standalone}
\usepackage{forest}
\usetikzlibrary{backgrounds}
\forestset{
  declare dimen register={timeline offset},
  timeline offset'=10mm,
  declare toks register={timeline target},
  timeline target=,
  declare boolean={tree node}{0},
  age/.code={
    \pgfkeys{/level age \foresteoption{level}/.initial={#1}}
  },
  mytree/.style={
    for tree={
      edge+={ultra thick},
      edge path'={
        (!u.parent anchor) -| (.child anchor)
      },
      grow'=north,
      parent anchor=children,
      child anchor=parent,
      anchor=base,
      l sep=1cm,
      s sep=3mm,
      if n children=0{tier=word, align=center, base=bottom, not tree node}{coordinate, tree node}
    }
  },
  timeline/.style={
    before drawing tree={
      timeline target/.option=name,
      tempdima/.option=y,
      for tree={
        if={>OR>{y}{tempdima}}{timeline target/.option=name}{},
      },
      tempcounta/.option=level,
      for nodewalk={
        filter={tree breadth-first}{>On>{n children}{0}}%
      }{
        if={
          >OR>{level}{tempcounta}%
        }{
          tempcounta/.option=level,
          tikz+={
            \edef\tempa{level age \foresteoption{level}}
            \begin{scope}[on background layer]
              \pgfkeys{/level age \foresteoption{level}/.get=\mylevelage}
              \draw [draw=gray, thick, dotted] () -- ( -| timeline base) node [left, anchor=east] {\mylevelage};
            \end{scope}
          }%
        }{}
      },
    },
    tikz+={
      \begin{scope}[on background layer]
        \draw ([xshift=-\foresteregister{timeline offset}]current bounding box.west |- .parent anchor) coordinate (timeline base) -- (\foresteregister{timeline target}.child anchor -| timeline base) node [above] {\textsc{mya}};
      \end{scope}
    },
  },
}

\begin{document}
\begin{forest}
  mytree,
  timeline
  [
    [, age=10
      [
        [gray fox]
        [island fox, age=4]
      ]
      [, age=7.4
        [
          [black\\bear]
          [giant\\panda]
        ]
        [
          [northern\\elephant\\seal]
          [walrus]
        ]
      ]
    ]
  ]
\end{forest}
\end{document}

输出如上。

相关内容