如何在 TikZ 中自动排列思维导图的节点(以避免重叠节点和连接)

如何在 TikZ 中自动排列思维导图的节点(以避免重叠节点和连接)

TikZ 中有一个用于创建思维导图(或概念导图)的库(https://pgf-tikz.github.io/pgf/pgfmanual.pdf#section.60)。

但是,使用起来似乎不太直观。我希望节点能够自动调整到其内容(部分可以通过以下方法实现https://tex.stackexchange.com/a/285655/194783)。

此外,我希望思维导图能够(至少是半)自动排列。

为了避免发生类似 MWE 的事情:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{mindmap}

\begin{document}
\pagestyle{empty}
{\centering
    \makebox[0pt]{
        \begin{tikzpicture}
            [mindmap,
            grow cyclic,
            every node/.style={concept, text width=},
            concept color=teal!40,
            ]
            \node {node}
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                };
        \end{tikzpicture}
    }
    \par
}
\end{document}

结果

我假设,在 CSS 中,人们将边距定义为具有不重叠的元素。

解决方案的一部分可能包括设置动态兄弟角度(例如https://tex.stackexchange.com/a/118746/194783)并定义自定义增长函数(如中所述https://tex.stackexchange.com/a/232914/194783)。

sibling angle编辑:为了缓解这个问题,我添加了一些代码来根据节点的子节点数量自动设置。但这仍然不能总是避免重叠。

我看过几篇关于编写自定义增长函数来实现特殊形状的帖子。这通常也能解决重叠问题,但我并不需要那里使用的形状。

对于相关问题,建议使用以下软件包forest,但对我的情况没有太大帮助:使用TikZ在树中重叠节点

答案1

所有功劳都归功于@Marmottopanswers.xyz/tex?q=1808

在此处输入图片描述

\documentclass[tikz,border=3mm]{standalone}

\usetikzlibrary{mindmap,shadows}

% growCycle

\makeatletter
\newif\ifmmap@debug
\mmap@debugfalse
\newcommand{\mmap@debug@message}[1]{\ifmmap@debug
    \typeout{#1}%
    \fi}
\def\tikz@mmap@store@aux#1#2{%
\immediate\write\@mainaux{\string\expandafter\xdef\noexpand\csname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\string\endcsname{#2}}}%
\def\tikz@mmap@get@from@aux#1#2{%
\ifcsname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\endcsname
\edef#2{\csname pgfk@/tikz/mmap/\pgfkeysvalueof{/tikz/mmap/name}/#1\endcsname}%
\else
\edef#2{0}%
\fi
}   
\pgfmathdeclarefunction{MMapNodesAtLevel}{1}{%
\tikz@mmap@get@from@aux{n-\@roman{#1}}{\pgfmathresult}}
\newcount\tikzcountchildi
\newcount\tikzcountchildii
\newcount\tikzcountchildiii
\newcount\tikzcountchildiv
\newcount\tikzcountchildv
\newcount\tikzcountchildvi
\tikzcountchildi=0
\tikzcountchildii=0
\tikzcountchildiii=0
\tikzcountchildiv=0
\tikzcountchildv=0
\tikzcountchildvi=0
\tikzset{Julien growth/.style={growth function=\tikz@grow@Julien,
    mmap/initialize counts,
    /tikz/execute at end scope={%
       \tikz@mmap@store@aux{n-i}{\the\tikzcountchildi}%
       \tikz@mmap@store@aux{n-ii}{\the\tikzcountchildii}%
       \tikz@mmap@store@aux{n-iii}{\the\tikzcountchildiii}%
       \tikz@mmap@store@aux{n-iv}{\the\tikzcountchildiv}%
       \tikz@mmap@store@aux{n-v}{\the\tikzcountchildv}%
       \tikz@mmap@store@aux{n-vi}{\the\tikzcountchildvi}%
    }},
    mmap/.cd,initialize counts/.code={\global\tikzcountchildi=0%
        \global\tikzcountchildii=0%
        \global\tikzcountchildiii=0%
        \global\tikzcountchildiv=0%
        \global\tikzcountchildv=0%
        \global\tikzcountchildvi=0%
    }
}


\def\tikz@grow@Julien{%
    \pgftransformreset% 
    \pgftransformshift{\pgfpoint{\pgfkeysvalueof{/tikz/mmap/overall xshift}}%
        {\pgfkeysvalueof{/tikz/mmap/overall yshift}}}%
    \ifcase\tikztreelevel 
    \or
        \pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildi}%
        \global\advance\tikzcountchildi by1\relax%
    \or
        \pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildii}%
        \global\advance\tikzcountchildii by1\relax%
    \or
        \pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildiii}%
        \global\advance\tikzcountchildiii by1\relax%
    \or
        \pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildiv}%
        \global\advance\tikzcountchildiv by1\relax%
    \or
        \pgfmathsetmacro{\pgfutil@tempb}{\pgfkeysvalueof{/tikz/mmap/overall rotation}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/offset angle}%
            +\pgfkeysvalueof{/tikz/mmap/sign}*\pgfkeysvalueof{/tikz/sibling angle}*\tikzcountchildv}%
        \global\advance\tikzcountchildv by1\relax%
    \fi
    \mmap@debug@message{level=\the\tikztreelevel,%
        \the\tikzcountchildi,\the\tikzcountchildii,\the\tikzcountchildiii,
        rotation=\pgfutil@tempb,sibling angle=\pgfkeysvalueof{/tikz/sibling angle}}%
    \pgftransformrotate{\pgfutil@tempb}%
    \pgftransformxshift{\the\tikzleveldistance}%
}
\makeatother
                
                
\tikzset{%
mmap/.cd,
    name/.initial=undef,
    overall rotation/.initial=0,
    overall xshift/.initial=0pt,
    overall yshift/.initial=0pt,
    sign/.initial=1,                
    child weight/.initial=0.5,      
/tikz/.cd,
    offset angle/.initial=0, %%% Not exist anymore
    Xshift/.style={xshift=#1,mmap/overall xshift=#1},
    Yshift/.style={yshift=#1,mmap/overall yshift=#1},
    branch color/.style={
        concept color=#1!80,ball color=#1!50,
        every child/.append style={concept color=#1!50},
    }
}


\begin{document}
    
% you may want to use pgf keys for those (did not change them)
\def\ShapeAngle{360}                % half circle
\def\Rotation{0}            
\def\DistOne{5cm}
\def\DistTwo{8cm}
\def\DistThree{11cm}
\def\OffsetLevelThree{0}


% Part to automate

\begin{tikzpicture}%[node font=\sffamily]                           
    \begin{scope}
        [   text width=1.5cm,
            align=flush center,
            mindmap,Julien growth,
            mmap/overall rotation=\Rotation,mmap/sign=1,
            mmap/name=semicirc,%<- you need unique names if you want to use several mindmaps
            every node/.style={concept,circular drop shadow,execute at begin node=\hskip0pt,text=white},    
            node font=\sffamily,
            nodes={concept},
            concept color=teal!40,
            root concept/.append style={ball color=teal!40, line width=1.5ex,text=white,font=\huge\bfseries\scshape,minimum size=4.5cm,text width=4.5cm,},                   
            level 1/.style={level distance=\DistOne,font=\large,minimum size=2.5cm,text width=2.0cm, 
            sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(1)-1),1)}},
            level 2/.style={level distance=\DistTwo,font=\normalsize,minimum size=1.5cm,text width=1.5cm, 
            sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(2)-1),1)}},
            level 3/.style={level distance=\DistThree,font=\normalsize,minimum size=1.5cm,text width=1.5cm, 
            sibling angle/.evaluated={\ShapeAngle/max((MMapNodesAtLevel(3)-1),1)},
            offset angle=\OffsetLevelThree},
        ]
        \node[root concept] {node} 
        child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                }
                child{
                    node {subnode}
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                    child { node {subnode} }
                };  
    \end{scope}
\end{tikzpicture}
\end{document}

相关内容