% Copyright (C) 2016-2021 by Paul Gaborit % % This file may be distributed and/or modified % % 1. under the LaTeX Project Public License and/or % % 2. under the GNU Public License. \def\sankey@version{2.0} \def\sankey@date{2021/01/27} \ProvidesPackage{sankey}[\sankey@date\space\sankey@version\space sankey package] \RequirePackage{xparse} \RequirePackage{xfp} \RequirePackage{tikz} \usetikzlibrary{calc,decorations.markings,dubins} \usepackage{etoolbox} % add a new layer to debug sankey diagrams \pgfdeclarelayer{background} \pgfdeclarelayer{foreground} \pgfdeclarelayer{sankeydebug} \pgfsetlayers{background,main,foreground,sankeydebug} % flag to debug sankey diagrams \newtoggle{sankey debug} \newtoggle{sankey node start} \newtoggle{sankey node end} % macros to store and to retrieve the orientation and the quantity % associated with each sankey node \def\sankeysetnodeqty#1#2{\expandafter\xdef\csname sankey@node@#1@qty\endcsname{#2}} \def\sankeygetnodeqty#1{% \ifcsmacro{sankey@node@#1@qty}{% \csname sankey@node@#1@qty\endcsname% }{% \PackageWarning{sankey}{Unknown sankey node '#1'}% }% } \def\sankeysetnodeorient#1#2{\expandafter\xdef\csname sankey@node@#1@orient\endcsname{#2}} \def\sankeygetnodeorient#1{% \ifcsmacro{sankey@node@#1@orient}{% \csname sankey@node@#1@orient\endcsname% }{% \PackageWarning{sankey}{Unknown sankey node '#1'}% }% } \def\sankeysetstartfill#1#2{\expandafter\gdef\csname sankey@start@fill@#1\endcsname{#2}} \def\sankeysetstartdraw#1#2{\expandafter\gdef\csname sankey@start@draw@#1\endcsname{#2}} \def\sankeysetendfill#1#2{\expandafter\gdef\csname sankey@end@fill@#1\endcsname{#2}} \def\sankeysetenddraw#1#2{\expandafter\gdef\csname sankey@end@draw@#1\endcsname{#2}} % \def\sankeygetstartfill#1{\csname sankey@start@fill@#1\endcsname} \def\sankeygetstartdraw#1{\csname sankey@start@draw@#1\endcsname} \def\sankeygetendfill#1{\csname sankey@end@fill@#1\endcsname} \def\sankeygetenddraw#1{\csname sankey@end@draw@#1\endcsname} % new shape \pgfdeclareshape{sankey node}{ \inheritsavedanchors[from=rectangle] \inheritanchor[from=rectangle]{center} %\inheritanchorborder[from=rectangle] \anchor{left}{\pgf@process{\northeast}} \anchor{right}{\pgf@process{\southwest}} } % pgfkeys family 'sankey' \pgfkeys{/sankey/.is family} \NewDocumentCommand\sankeyset{m}{\pgfkeys{sankey,#1}} \sankeyset{ ratio length/.code={ \pgfmathsetmacro\sankeytotallen{#1} \edef\sankeytotallen{\sankeytotallen pt} }, ratio length/.value required, ratio quantity/.code={\edef\sankeytotalqty{\fpeval{#1}}}, ratio quantity/.value required, ratio/.style args={#1/#2}{ ratio length=#1, ratio quantity=#2, }, ratio/.value required, minimum radius/.estore in=\sankeyminradius, minimum radius/.value required, outin steps/.estore in=\sankeystepoutin, outon steps/.value required, % debug/.is choice, debug/true/.code={\toggletrue{sankey debug}}, debug/false/.code={\togglefalse{sankey debug}}, debug/.default=true, % start style/.is choice, % end style/.is choice, % default values default parameters/.style={ % default values ratio=1cm/10, minimum radius=5mm,% outin steps=10, debug=false, start style=none, end style=none, }, % to make node node parameters/.style={ quantity/.code={% %\typeout{quantity=##1}% \edef\qty{\fpeval{##1}}% %\typeout{qty=\qty}% }, quantity/.value required, angle/.code={% %\typeout{angle:##1}% \pgfmathsetmacro\orient{##1}% }, angle/.value required, name/.store in=\name, name/.value required, at/.store in=\pos, at/.value required, as/.style={ name=##1, quantity=\sankeygetnodeqty{##1}, angle=\sankeygetnodeorient{##1}, at={##1.center}, }, as/.value required, % anchor/.is choice, anchor/left/.code={\def\sankeyanchor{left}}, anchor/right/.code={\def\sankeyanchor{right}}, anchor/center/.code={\def\sankeyanchor{center}}, anchor=center, % start/.is choice, start/true/.code={\toggletrue{sankey node start}}, start/false/.code={\togglefalse{sankey node start}}, start/.default=true, start=false, % end/.is choice, end/true/.code={\toggletrue{sankey node end}}, end/false/.code={\togglefalse{sankey node end}}, end/.default=true, end=false, }, } % some styles \sankeyset{ node/.style={ shape=sankey node, inner sep=0,minimum height={\sankeyqtytolen{#1}}, minimum width=0,draw=none,line width=0pt, node contents={}, }, fill/.style={line width=0pt,fill=white}, draw/.style={draw=black,line width=.4pt}, % debug color used by all debug macros debug color/.style={/utils/exec={\colorlet{debug color}{#1}}}, debug color=red!75!black, % debug line between left and right anchors debug line/.style={draw=debug color,|-|}, % debug line between center and label debug normal/.style={draw=debug color}, % debug node label debug label/.style={ draw, font=\ttfamily\tiny, text=debug color,text opacity=1, inner sep=.1em, fill=white,fill opacity=1, rounded corners=.1em, }, } \sankeyset{ new start style/.code n args={3}{% name, fill path, draw path \sankeysetstartfill{#1}{#2} \sankeysetstartdraw{#1}{#3} \sankeyset{start style/#1/.code={\def\sankeystartstyle{#1}}} }, new end style/.code n args={3}{% name, fill path, draw path \sankeysetendfill{#1}{#2} \sankeysetenddraw{#1}{#3} \sankeyset{end style/#1/.code={\def\sankeyendstyle{#1}}} }, } % the new 'sankeydiagram' environment \NewDocumentEnvironment{sankeydiagram}{O{}+b}{ \newcommand\sankeyarc[2]{% sn, en \begingroup \pgfmathsetmacro\startangle{\sankeygetnodeorient{##1}} \pgfmathsetmacro\endangle{\sankeygetnodeorient{##2}} \pgfmathsetmacro\rotateangle{\endangle-\startangle} \pgfmathtruncatemacro\acwrotate{\rotateangle>0?1:0} \path let \p1=(##1.left),\p2=(##1.right), \p3=(##2.left),\p4=(##2.right), \n1={\sankeyqtytolen{\sankeygetnodeqty{##1}}}, \n{maxr}={\sankeyminradius+\n1}, \n{minr}={\sankeyminradius} in \pgfextra{ \ifnumequal{\acwrotate}{1}{ \begin{pgfinterruptpath} % fill the region \path[/sankey/fill] (\p1) arc(\startangle-90:\endangle-90:\n{minr}) -- (\p3) -- (\p4) arc(\endangle-90:\startangle-90:\n{maxr}) -- (\p2) -- cycle; % draw left and right borders \path[/sankey/draw] (\p1) arc(\startangle-90:\endangle-90:\n{minr}) (\p4) arc(\endangle-90:\startangle-90:\n{maxr}); \end{pgfinterruptpath} }{ \begin{pgfinterruptpath} % fill the region \path[/sankey/fill] (\p1) arc(\startangle+90:\endangle+90:\n{maxr}) -- (\p3) -- (\p4) arc(\endangle+90:\startangle+90:\n{minr}) -- (\p2) -- cycle; % draw left and right borders \path[/sankey/draw] (\p1) arc(\startangle+90:\endangle+90:\n{maxr}) (\p4) arc(\endangle+90:\startangle+90:\n{minr}); \end{pgfinterruptpath} } }; \endgroup } \newcommand\sankeymakenodenodebug{ \begingroup \sankeysetnodeqty{\name}{\qty} \sankeysetnodeorient{\name}{\orient} % \typeout{\qty,\orient} \ifundef{\sankeyanchor}{\def\sankeyanchor{center}}{} \node[/sankey/node=\qty,rotate=\orient,at/.expanded={(\pos)},name=\name,anchor=\sankeyanchor]; \endgroup } \newcommand\sankeymakenode{ \begingroup \sankeymakenodenodebug{} \iftoggle{sankey debug}{ \begin{pgfonlayer}{sankeydebug} \pgfset{ number format/relative*=-1, number format/precision=1, number format/fixed, } \path[/sankey/debug line] (\name.left) -- (\name.right); \pgfmathsetmacro{\len}{\sankeyqtytolen{\qty}/3} \path[/sankey/debug normal] (\name.center) -- ($(\name.center)!\len pt!90:(\name.right)$) node[/sankey/debug label,rotate=\orient+90,anchor=north] {\name:\pgfmathprintnumber{\qty}}; \end{pgfonlayer} }{} \endgroup } \newcommand\sankeynodenodebug[1]{ \begingroup \sankeyset{node parameters,##1} %\typeout{sankeynodenodebug: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeymakenodenodebug{} \endgroup } % ============================================================ % user commands % ============================================================ \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en \begingroup \sankeyset{##1} \pgfmathsetmacro\startangle{\sankeygetnodeorient{##2}} \pgfmathsetmacro\endangle{\sankeygetnodeorient{##3}} \edef\sqty{\sankeygetnodeqty{##2}} \edef\eqty{\sankeygetnodeqty{##3}} \ifdefstrequal{\sqty}{\eqty}{}{ \PackageError{sankey}% {^^J*** \string\sankeyoutin: quantities differ between ##2 (\sqty) and ##3 (\eqty)^^J}% {The quantities of the two Sankey nodes must be equal.} } \pgfmathsetmacro\qty{\sankeygetnodeqty{##2}} \pgfmathsetmacro\width{\sankeyqtytolen{\qty}} %\typeout{startangle:\startangle,endangle:\endangle,qty:\qty,width:\width} \dubinspathset{ sankey/.style={ start point=##2.center,start angle=\startangle, end point=##3.center,end angle=\endangle, minimum radius=\sankeyminradius + .5 * \width pt, }, } \dubinspathcalc{sankey,store=sankey} \dubinspathset{ left border/.style={ sankey, use store=sankey, left and right minimum radii= {\sankeyminradius} and {\sankeyminradius + \width pt}, }, right border/.style={ sankey, use store=sankey, left and right minimum radii= {\sankeyminradius + \width pt} and {\sankeyminradius}, }, } \path let \p1=(##2.left),\p2=(##2.right), \p3=(##3.left),\p4=(##3.right) in \pgfextra{ \begin{pgfinterruptpath} % fill the region \path[/sankey/fill] (\p1) \dubinspath{left border} -- (\p3) -- (\p4) \dubinspath{right border,reverse} -- (\p2) -- cycle; % draw left and right borders \path[/sankey/draw] (\p1) \dubinspath{left border} (\p2) \dubinspath{right border} ; \end{pgfinterruptpath} }; \endgroup } \NewDocumentCommand\sankeyoutin{O{}mm}{% options, sn, en \begingroup \sankeyset{##1} \edef\sn{##2} \edef\en{##3} \edef\sqty{\sankeygetnodeqty{\sn}} \edef\eqty{\sankeygetnodeqty{\en}} \ifdefstrequal{\sqty}{\eqty}{}{ \PackageError{sankey}% {^^J*** \string\sankeyoutin: quantities differ between \sn (\sqty) and \en (\eqty)^^J}% {The quantities of the two Sankey nodes must be equal.} } %\typeout{*** sankeyoutin: \sn\space to \en\space (\sankeystepoutin)} \pgfmathsetmacro\qty{\sankeygetnodeqty{\sn}} \pgfmathsetmacro\mylength{\sankeyqtytolen{\qty}/2} \pgfmathsetmacro\mystep{1/\sankeystepoutin} %\typeout{*** a} \pgfmathsetmacro\mybound{1-.5*\mystep} %\typeout{*** b} \pgfmathsetmacro\laststep{int(\sankeystepoutin-1)} %\typeout{sankeystepoutin(\sankeystepoutin) mystep(\mystep) mybound(\mybound) laststep(\laststep)} %\typeout{*** sankeyoutin: \startangle to \endangle} \path[decorate,overlay,decoration={ markings, mark=between positions \mystep and \mybound step \mystep with { \def\sankeyoutinmidptname{sankeyoutinmidpt \pgfkeysvalueof{/pgf/decoration/mark info/sequence number}} \path (0,0) coordinate(\sankeyoutinmidptname) (0,-\mylength pt) coordinate (\sankeyoutinmidptname\space r) (0,\mylength pt) coordinate (\sankeyoutinmidptname\space l) ; } }](\sn.center) to[out=\sankeygetnodeorient{\sn},in=\sankeygetnodeorient{\en}+180] (\en.center); \foreach \myptnum in {1,...,\laststep}{ \def\sankeyoutinmidptname{sankeyoutinmidpt \myptnum} \anglebetween\sankeyoutinmidptangle{\sankeyoutinmidptname\space r}{\sankeyoutinmidptname\space l} \sankeynodenodebug{quantity=\qty,angle=\sankeyoutinmidptangle-90,name=\sankeyoutinmidptname,at=\sankeyoutinmidptname} } \sankeynodenodebug{quantity=\sankeygetnodeqty{\sn},angle=\sankeygetnodeorient{\sn},name={sankeyoutinmidpt 0},at={\sn}} \sankeynodenodebug{quantity={\sankeygetnodeqty{\en}},angle={\sankeygetnodeorient{\en}},name={sankeyoutinmidpt \sankeystepoutin},at={\en}} %\typeout{*********************} \path[/sankey/fill,looseness=1] (sankeyoutinmidpt 0.left) \foreach \curpt[remember=\curpt as \prevpt (initially 0)] in {1,...,\sankeystepoutin}{ to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt},in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}+180] (sankeyoutinmidpt \curpt.left) } -- (sankeyoutinmidpt \sankeystepoutin.right) \foreach \curpt[remember=\curpt as \prevpt (initially \sankeystepoutin)] in {\laststep,...,0}{ to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt}+180,in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}] (sankeyoutinmidpt \curpt.right) } -- cycle; \path[/sankey/draw,looseness=1] (sankeyoutinmidpt 0.left) \foreach \curpt[remember=\curpt as \prevpt (initially 0)] in {1,...,\sankeystepoutin}{ to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt},in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}+180] (sankeyoutinmidpt \curpt.left) } % (sankeyoutinmidpt \sankeystepoutin.right) \foreach \curpt[remember=\curpt as \prevpt (initially \sankeystepoutin)] in {\laststep,...,0}{ to[out=\sankeygetnodeorient{sankeyoutinmidpt \prevpt}+180,in=\sankeygetnodeorient{sankeyoutinmidpt \curpt}] (sankeyoutinmidpt \curpt.right) } ; \endgroup } \NewDocumentCommand\sankeynodealias{mm}{%name, alias \path [late options={name=##1,alias=##2}]; \sankeysetnodeqty{##2}{\sankeygetnodeqty{##1}} \sankeysetnodeorient{##2}{\sankeygetnodeorient{##1}} } \newcommand\sankeynode[2][]{ \begingroup \sankeyset{##1} \sankeyset{node parameters,##2} %\typeout{sankeynode: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeymakenode{} \endgroup } \def\sankeyfilldrawstart{ \begin{scope}[shift={(\name)},rotate=\orient] \path[/sankey/fill] \sankeygetstartfill{\sankeystartstyle}; \path[/sankey/draw] \sankeygetstartdraw{\sankeystartstyle}; \end{scope} } \NewDocumentCommand\sankeystart{O{}m}{ \begingroup \sankeyset{##1} \edef\name{##2} \edef\orient{\sankeygetnodeorient{##2}} \edef\qty{\sankeygetnodeqty{##2}} \sankeyfilldrawstart \endgroup } \NewDocumentCommand\sankeynodestart{O{}m}{ \begingroup %\typeout{sankeynodestart: ##2} \sankeyset{##1} \sankeyset{node parameters,##2} %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeymakenode{} %\typeout{sankeynodestart: sankeynode ok} %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeyfilldrawstart \endgroup } \def\sankeyfilldrawend{ \begin{scope}[shift={(\name)},rotate=\sankeygetnodeorient{\name}] \path[/sankey/fill] \sankeygetendfill{\sankeyendstyle}; \path[/sankey/draw] \sankeygetenddraw{\sankeyendstyle}; \end{scope} } \NewDocumentCommand\sankeyend{O{}m}{%name \begingroup \sankeyset{##1} \edef\name{##2} \edef\orient{\sankeygetnodeorient{##2}} \edef\qty{\sankeygetnodeqty{##2}} \sankeyfilldrawend \endgroup } \NewDocumentCommand\sankeynodeend{O{}m}{ \begingroup %\typeout{sankeynodestart: ##2} \sankeyset{##1} \sankeyset{node parameters,##2} %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeymakenode{} %\typeout{sankeynodestart: sankeynode ok} %\typeout{sankeynodestart: '\name' at(\pos) angle(\orient) qty(\qty)} \sankeyfilldrawend \endgroup } \NewDocumentCommand\sankeyadvance{sO{}mm}{% *(reverse), options, name, distance \begingroup \sankeyset{##2} \def\newname{##3} \def\oldname{##3-old} \sankeynodealias{\newname}{\oldname} % \typeout{*** sankeyadvance: ok (\oldname => \newname)} \IfBooleanTF{##1}{ % reverse advance \sankeynode{ at={$(\oldname.center)!##4!90:(\oldname.left)$}, angle=\sankeygetnodeorient{\oldname}, quantity=\sankeygetnodeqty{\oldname}, name=\newname, } \path[/sankey/fill] (\newname.left) -- (\oldname.left) -- (\oldname.right) -- (\newname.right) -- cycle; \path[/sankey/draw] (\newname.left) -- (\oldname.left) (\oldname.right) -- (\newname.right); \endgroup }{ % advance \sankeynode{ at={$(\oldname.center)!##4!-90:(\oldname.left)$}, angle=\sankeygetnodeorient{\oldname}, quantity=\sankeygetnodeqty{\oldname}, name=\newname, } \path[/sankey/fill] (\oldname.left) -- (\newname.left) -- (\newname.right) -- (\oldname.right) -- cycle; \path[/sankey/draw] (\oldname.left) -- (\newname.left) (\newname.right) -- (\oldname.right); \endgroup } } \NewDocumentCommand\sankeyturn{sO{}mm}{% *(reverse), options, name, angle \begingroup \sankeyset{##2} \def\name{##3} \def\oldname{##3-old} \sankeynodealias{\name}{\oldname} \pgfmathsetmacro\qty{\sankeygetnodeqty{\oldname}} \pgfmathsetmacro\oldangle{\sankeygetnodeorient{\oldname}} \IfBooleanTF{##1}{ % turn in reverse \pgfmathsetmacro\orient{\oldangle-##4} % \typeout{TURN: \oldangle=>\orient} \ifnumgreater{##4}{0}{% anti-clockwise turn \path let \p1=(##3.left), \p2=(##3.right), % center of rotation \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), % starting position \p{s}=(##3.center), % ending position \p{e}=($(\p{c})!1!-##4:(\p{s})$) in \pgfextra{ \begin{pgfinterruptpath} % \typeout{acw turn:\qty:\orient} \def\pos{\p{e}} \sankeymakenode{} \sankeyarc{\name}{\oldname} \end{pgfinterruptpath} }; }{ % clockwise turn \path let \p1=(##3.right), \p2=(##3.left), % center of rotation \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), % starting position \p{s}=(##3.center), % ending position \p{e}=($(\p{c})!1!-##4:(\p{s})$) in \pgfextra{ % \typeout{cw turn:\qty:\orient} \begin{pgfinterruptpath} \def\pos{\p{e}} \sankeymakenode{} \sankeyarc{\name}{\oldname} \end{pgfinterruptpath} }; } }{ % turn \pgfmathsetmacro\orient{\oldangle+##4} % \typeout{TURN: \oldangle=>\orient} \ifnumgreater{##4}{0}{% anti-clockwise turn \path let \p1=(##3.left), \p2=(##3.right), % center of rotation \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), % starting position \p{s}=(##3.center), % ending position \p{e}=($(\p{c})!1!##4:(\p{s})$) in \pgfextra{ \begin{pgfinterruptpath} % \typeout{acw turn:\qty:\orient} \def\pos{\p{e}} \sankeymakenode{} \sankeyarc{\oldname}{\name} \end{pgfinterruptpath} }; }{ % clockwise turn \path let \p1=(##3.right), \p2=(##3.left), % center of rotation \p{c}=($(\p1)!-\sankeyminradius!(\p2)$), % starting position \p{s}=(##3.center), % ending position \p{e}=($(\p{c})!1!##4:(\p{s})$) in \pgfextra{ % \typeout{cw turn:\qty:\orient} \begin{pgfinterruptpath} \def\pos{\p{e}} \sankeymakenode{} \sankeyarc{\oldname}{\name} \end{pgfinterruptpath} }; } } \endgroup } \NewDocumentCommand\sankeyfork{mm}{%name,list of forks \def\listofforks{##2} \xdef\sankeytot{0} \xdef\sankeycalculus{0} \pgfmathsetmacro\iqty{\sankeygetnodeqty{##1}} \pgfmathsetmacro\iorient{\sankeygetnodeorient{##1}} \pgfmathsetmacro\orient{\iorient} %\typeout{iname:##1, iqty:\iqty,iorient:\iorient} \foreach \qty/\name[count=\c] in \listofforks { %\typeout{sankeyfork foreach: qty(\qty) name(\name) count(\c)} \path let \p1=(##1.left),\p2=(##1.right), \p{start}=($(\p1)!\fpeval{\sankeytot/\iqty}!(\p2)$), \n{nexttot}={\fpeval{\sankeytot+\qty}}, \p{end}=($(\p1)!\fpeval{\n{nexttot}/\iqty}!(\p2)$), \p{mid}=($(\p{start})!.5!(\p{end})$) in \pgfextra{ %\typeout{new fork:\name} %\typeout{qty:\qty,name:\name,count:\c,pos=\p{mid}} \xdef\sankeytot{\n{nexttot}} \xdef\sankeycalculus{\fpeval{\sankeycalculus+\qty}} \begin{pgfinterruptpath} \def\pos{\p{mid}} \sankeymakenode{} \end{pgfinterruptpath} }; } \edef\diff{\fpeval{abs(\iqty-\sankeytot)}} %\typeout{sankeyfork diff: \diff} %\pgfmathsetmacro{\diff}{abs(\iqty-\sankeytot)} %\pgfmathtruncatemacro{\finish}{\diff<0.01?1:0} \ifnumequal{\diff}{0}{}{ \PackageWarning{sankey}{^^J*** Warning: bad sankey fork: \iqty\space!=\space\sankeycalculus(=\sankeytot)^^J##2} } } \def\sankeyqtytolen##1{\fpeval{(##1)/\sankeytotalqty*\sankeytotallen}} \sankeyset{ % % default values, % /tikz/declare function={ % % sankeyqtytolen(\qty)=\qty/\sankeytotalqty*\sankeytotallen; % % sankeylentoqty(\len)=\len/\sankeytotallen*\sankeytotalqty; % },% default parameters,% % user values #1} %\typeout{sankeytotallen: \sankeytotallen} #2 % body of sankeydiagram environment } \sankeyset{ % none style new start style={none}{}{}, new end style={none}{}{}, % simple style new start style={simple}{ (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) -- cycle }{ (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right) }, new end style={simple}{ (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) -- cycle }{ (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) }, % arrow style new start style={arrow}{ (\name.left) -- ++(-10pt,0) -- ([xshift=-10pt/6]\name.center) -- ([xshift=-10pt]\name.right) -- (\name.right) -- cycle }{ (\name.left) -- ++(-10pt,0) -- ([xshift=-10pt/6]\name.center) -- ([xshift=-10pt]\name.right) -- (\name.right) }, new end style={arrow}{ (\name.left) -- ([yshift=1mm]\name.left) -- ([xshift=10pt]\name.center) -- ([yshift=-1mm]\name.right) -- (\name.right) -- cycle }{ (\name.left) -- ([yshift=1mm]\name.left) -- ([xshift=10pt]\name.center) -- ([yshift=-1mm]\name.right) -- (\name.right) }, }