summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/sankey/sankey.sty
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2021-03-14 22:49:02 +0000
committerKarl Berry <karl@freefriends.org>2021-03-14 22:49:02 +0000
commit11cb80cef7eaad10df3ed09d6d5a50ad2c055881 (patch)
treed61dcff1e45fad3df683797a9fa17e91e2fb7bdd /Master/texmf-dist/tex/latex/sankey/sankey.sty
parentfd1e514f7290c40fb1e5c37994e7756c4d73348d (diff)
sankey (14mar21)
git-svn-id: svn://tug.org/texlive/trunk@58349 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/sankey/sankey.sty')
-rw-r--r--Master/texmf-dist/tex/latex/sankey/sankey.sty1201
1 files changed, 645 insertions, 556 deletions
diff --git a/Master/texmf-dist/tex/latex/sankey/sankey.sty b/Master/texmf-dist/tex/latex/sankey/sankey.sty
index 4c28a1fe0d4..b6734004f77 100644
--- a/Master/texmf-dist/tex/latex/sankey/sankey.sty
+++ b/Master/texmf-dist/tex/latex/sankey/sankey.sty
@@ -1,722 +1,811 @@
-% 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]
-
+%%
+%% This is file `sankey.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% sankey.dtx (with options: `sankey')
+%%
+%% This is a generated file.
+%%
+%% Copyright (C) 2016, 2021 by Paul Gaborit
+%%
+%% This work may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License, either version 1.3 of this license or (at
+%% your option) any later version. The latest version of this license is
+%% in
+%%
+%% <http://www.latex-project.org/lppl.txt>
+%%
+%% and version 1.3 or later is part of all distributions of LaTeX version
+%% 2005/12/01 or later.
+%%
+%% This work has the LPPL maintenance status “maintained”.
+%%
+%% The Current Maintainer of this work is Paul Gaborit.
+%%
+%% This work consists of the files sankey.dtx, sankey.ins and the derived
+%% files sankey.sty, tikzlibrarydubins.code.tex, sankey-doc-preamble.sty,
+%% sankey-example1.tex, sankey-example2.tex, sankey-example3.tex,
+%% sankey-example3-variation.tex, sankey-example4.tex,
+%% sankey-example-energy.tex
+%%
+\NeedsTeXFormat{LaTeX2e}[2015/10/01]
+\ProvidesPackage{sankey}[2021/03/14 v3.0 to draw Sankey diagrams]
\RequirePackage{xparse}
+\RequirePackage{etoolbox}
\RequirePackage{xfp}
\RequirePackage{tikz}
-\usetikzlibrary{calc,decorations.markings,dubins}
-\usepackage{etoolbox}
-
-% add a new layer to debug sankey diagrams
+\usetikzlibrary{
+ calc,
+ decorations.markings,
+ dubins
+}
+%% 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\snk@newfield#1#2#3#4#5{
+ % setter
+ \def#2##1##2{\expandafter#1\csname #4\endcsname{##2}}
+ % getter
+ \def#3##1{%
+ \ifcsdef{#4}{%
+ \csname#4\endcsname%
+ }{%
+ \PackageError{sankey}{#5}{unknown key with \string#3}%
+ }%
+ }
}
-
-\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'}%
- }%
+\snk@newfield\xdef\snk@setnodeqty\sankeygetnodeqty%
+{@snk@node@qty@#1}{Unknown sankey node '#1'}
+\snk@newfield\xdef\snk@setnodeorient\sankeygetnodeorient%
+{@snk@node@orient@#1}{Unknown sankey node '#1'}
+\snk@newfield\def\snk@setstartfill\snk@getstartfill%
+{@snk@start@fill@#1}{Unknown sankey start fill path #1}
+
+\snk@newfield\def\snk@setstartdraw\snk@getstartdraw%
+{@snk@start@draw@#1}{Unknown sankey start draw path #1}
+\snk@newfield\def\snk@setendfill\snk@getendfill%
+{@snk@end@fill@#1}{Unknown sankey end fill path #1}
+
+\snk@newfield\def\snk@setenddraw\snk@getenddraw%
+{@snk@end@draw@#1}{Unknown sankey end draw path #1}
+
+\newcommand\snk@ifnodedefined[3]{%
+ \ifcsdef{@snk@node@qty@#1}{#2}{#3}%
+}
+\newcommand\snk@errorifnotdefined[1]{%
+ \snk@ifnodedefined{#1}{}%
+ {\PackageError{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]
+ \inheritanchorborder[from=rectangle]
\anchor{left}{\pgf@process{\northeast}}
\anchor{right}{\pgf@process{\southwest}}
+ % compatibility with 'fit' library
+ \inheritanchor[from=rectangle]{west}
+ \inheritanchor[from=rectangle]{east}
+ \inheritanchor[from=rectangle]{north}
+ \inheritanchor[from=rectangle]{south}
+ \inheritanchor[from=rectangle]{north west}
+ \inheritanchor[from=rectangle]{south east}
+ \inheritanchor[from=rectangle]{north east}
+ \inheritanchor[from=rectangle]{south west}
}
-
-% pgfkeys family 'sankey'
\pgfkeys{/sankey/.is family}
-
\NewDocumentCommand\sankeyset{m}{\pgfkeys{sankey,#1}}
-
\sankeyset{
+ ratio quantity/.code={\edef\snk@totalqty{\fpeval{#1}}},
+ ratio quantity/.value required,
ratio length/.code={
- \pgfmathsetmacro\sankeytotallen{#1}
- \edef\sankeytotallen{\sankeytotallen pt}
+ \pgfmathsetmacro\snk@totallen{#1}
+ \edef\snk@totallen{\snk@totallen 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,
+}
+\sankeyset{
+ rotate/.code={\edef\snk@rotate{\fpeval{#1}}},
+ rotate/.value required,
+}
+\sankeyset{
+ minimum radius/.code={
+ \pgfmathsetmacro\snk@minradius{#1}
+ \edef\snk@minradius{\snk@minradius pt}
+ },
minimum radius/.value required,
- outin steps/.estore in=\sankeystepoutin,
+}
+\sankeyset{
+ outin steps/.estore in=\snk@stepoutin,
outon steps/.value required,
- %
+}
+\newtoggle{sankey debug}
+\sankeyset{
debug/.is choice,
debug/true/.code={\toggletrue{sankey debug}},
debug/false/.code={\togglefalse{sankey debug}},
debug/.default=true,
- %
+}
+\sankeyset{
start style/.is choice,
- %
end style/.is choice,
- % default values
- default parameters/.style={
- % default values
+ % to define new start and end styles
+ new start style/.code n args={3}{% name, fill path, draw path
+ \snk@setstartfill{#1}{#2}
+ \snk@setstartdraw{#1}{#3}
+ \sankeyset{start style/#1/.code={\def\snk@startstyle{#1}}}
+ },
+ new end style/.code n args={3}{% name, fill path, draw path
+ \snk@setendfill{#1}{#2}
+ \snk@setenddraw{#1}{#3}
+ \sankeyset{end style/#1/.code={\def\snk@endstyle{#1}}}
+ },
+}
+\sankeyset{
+ debug color/.style={/utils/exec={\colorlet{debug color}{#1}}},
+ @initial options/.style={
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}%
+ rotate=0,
+ % default fill/draw styles,
+ fill/.style={line width=0pt,fill=white},
+ draw/.style={draw=black,line width=.4pt},
+ % debug color used by all debug macros
+ debug color=red!75!black,
+ % debug line between left and right anchors
+ debug line/.style={overlay,draw=debug color,|-|},
+ % debug line between center and label
+ debug normal/.style={overlay,draw=debug color},
+ % debug node label
+ debug label/.style={
+ overlay,
+ draw,
+ font=\ttfamily\tiny,
+ text=debug color,text opacity=1,
+ inner sep=.1em,
+ fill=white,fill opacity=1,
+ rounded corners=.1em,
+ node contents={\name},
},
- 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,
+ every node/.style={},
},
+ every diagram/.style={},
}
-% 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={},
+\sankeyset{node parameters/.is family}
+\sankeyset{node parameters,
+ name/.estore in=\name,
+ name/.value required,
+ quantity/.code={\edef\qty{\fpeval{#1}}},
+ quantity/.value required,
+ angle/.code={\edef\orient{\snk@normalize@angle{#1}}},
+ angle/.value required,
+ at/.code={\snk@getpos\pos{#1}},
+ at/.value required,
+}
+\sankeyset{node parameters,
+ as/.style={
+ name=#1,
+ quantity=\sankeygetnodeqty{#1},
+ angle=\sankeygetnodeorient{#1},
+ at={#1.center},
},
- 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,
+ as/.value required,
+}
+\sankeyset{node parameters,
+ anchor/.is choice,
+ anchor/left/.code={\def\snk@anchor{left}},
+ anchor/right/.code={\def\snk@anchor{right}},
+ anchor/center/.code={\def\snk@anchor{center}},
+ anchor/.value required,
+}
+\newtoggle{sankey node start}
+\newtoggle{sankey node end}
+\sankeyset{node parameters,
+ start/.is choice,
+ start/true/.code={\toggletrue{sankey node start}},
+ start/false/.code={\togglefalse{sankey node start}},
+ start/.default=true,
+ %
+ end/.is choice,
+ end/true/.code={\toggletrue{sankey node end}},
+ end/false/.code={\togglefalse{sankey node end}},
+ end/.default=true,
+}
+\sankeyset{node parameters,
+ forked/.estore in=\snk@listofforks,
+ forked/.value required,
+ fork anchor/.estore in=\snk@forkanchor,
+ fork anchor/.value required,
+}
+\sankeyset{node parameters,
+ @initial parameters/.style={
+ start=false,
+ end=false,
+ forked=,
+ fork anchor=,
+ anchor=center,
+ at={0,0},
+ angle=0,
},
}
-
\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}}}
+ % sankey node TikZ style
+ @sankey node/.style n args={3}{% name, pos, anchor
+ shape=sankey node,
+ inner sep=0,
+ minimum height={\sankeyqtytolen{\sankeygetnodeqty{#1}}},
+ minimum width=0,
+ draw=none,
+ line width=0pt,
+ fill=none,
+ node contents={},
+ rotate=\sankeygetnodeorient{#1}+\snk@rotate,
+ at={(#2)},
+ name=#1,
+ anchor=#3,
},
}
-
-% 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
+\NewDocumentEnvironment{sankeydiagram}{O{}}{
+ \def\snk@getpos##1##2{%
+ \tikz@scan@one@point\pgfutil@firstofone(##2)\relax%
+ \edef##1{\the\pgf@x,\the\pgf@y}%
}
-
- \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
+ \def\snk@modulo##1##2{\fpeval{##1-(floor((##1)/(##2),0)*##2)}}
+ \def\snk@normalize@angle##1{%
+ \fpeval{\snk@modulo{(##1)+180}{360}-180}%
}
-
- \newcommand\sankeymakenode{
- \begingroup
- \sankeymakenodenodebug{}
+ \def\snk@show@debug##1{% node name
\iftoggle{sankey debug}{
+ \begingroup
+ \edef\name{##1}
+ \edef\qty{\sankeygetnodeqty{\name}}
+ \edef\orient{\sankeygetnodeorient{\name}}
\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}
+ \pgfmathsetmacro{\snk@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}};
+ -- ($(\name.center)!\snk@len pt!90:(\name.right)$)
+ node[/sankey/debug label,rotate=\orient+90+\snk@rotate,anchor=north];
\end{pgfonlayer}
+ \endgroup
}{}
+ }
+ \def\snk@makeforkednode{
+ \begingroup
+ \ifdefempty{\snk@listofforks}{
+ \ifdefempty{\snk@forkanchor}{}{
+ \PackageWarning{sankey}%
+ {Can't use 'fork anchor' key without 'forked' key}
+ }
+ }{
+ \def\snk@tot{0}
+ \def\snk@added@values{}
+ \sankeyset{
+ @add forked node/.code args={####1/####2}{
+ \coordinate (####2) at ($(\name.left)%
+ !\fpeval{(\snk@tot+.5*(####1))/\qty}%
+ !(\name.right)$);
+ \edef\snk@orient{\orient}
+ \sankeynode[debug=false]
+ {name=####2,quantity=####1,at=####2,angle=\snk@orient}
+ \edef\snk@tot{\fpeval{\snk@tot+####1}}
+ \edef\snk@added@values{\snk@added@values+####1}
+ },
+ @add forked node/.list/.expand once=\snk@listofforks,
+ }
+ \edef\snk@diff{\fpeval{abs(\qty-\snk@tot)}}
+ \ifnumequal{\snk@diff}{0}{}{
+ \PackageWarning{sankey}%
+ {^^J*** Warning: bad sankey fork: %
+ \qty\space!=\space\snk@added@values(=\snk@tot)%
+ ^^J\snk@listofforks}
+ }
+ \ifdefempty{\snk@forkanchor}{
+ \edef\snk@forkanchor{\name.\snk@anchor}
+ }{}
+ \snk@getpos\snk@c{$(\snk@forkanchor) - (\pos)$}
+ \sankeynode{as=\name,at={$(\name) - (\snk@c)$}}
+ \foreach \snk@subnodeqty/\snk@subnodename in \snk@listofforks {
+ \sankeynode{as=\snk@subnodename,at={$(\snk@subnodename) - (\snk@c)$}}
+ }
+ }
\endgroup
}
-
- \newcommand\sankeynodenodebug[1]{
+ \def\snk@makenode{
\begingroup
- \sankeyset{node parameters,##1}
- %\typeout{sankeynodenodebug: '\name' at(\pos) angle(\orient) qty(\qty)}
- \sankeymakenodenodebug{}
+ \snk@setnodeqty{\name}{\qty}
+ \edef\orient{\snk@normalize@angle{\orient}}
+ \snk@setnodeorient{\name}{\orient}
+ \ifundef{\snk@anchor}{\def\snk@anchor{center}}{}
+ \node[/sankey/@sankey node={\name}{\pos}{\snk@anchor}];
\endgroup
}
-
- % ============================================================
- % user commands
- % ============================================================
-
- \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en
+ \def\snk@filldrawstart{
+ \begin{scope}[shift={(\name)},rotate=\orient]
+ \path[/sankey/fill] \snk@getstartfill{\snk@startstyle};
+ \path[/sankey/draw] \snk@getstartdraw{\snk@startstyle};
+ \end{scope}
+ }
+ \def\snk@filldrawend{
+ \begin{scope}[shift={(\name)},rotate=\sankeygetnodeorient{\name}]
+ \path[/sankey/fill] \snk@getendfill{\snk@endstyle};
+ \path[/sankey/draw] \snk@getenddraw{\snk@endstyle};
+ \end{scope}
+ }
+ \def\snk@checkquantities##1##2##3{
\begingroup
- \sankeyset{##1}
- \pgfmathsetmacro\startangle{\sankeygetnodeorient{##2}}
- \pgfmathsetmacro\endangle{\sankeygetnodeorient{##3}}
- \edef\sqty{\sankeygetnodeqty{##2}}
- \edef\eqty{\sankeygetnodeqty{##3}}
- \ifdefstrequal{\sqty}{\eqty}{}{
+ \edef\snk@qtyi{\sankeygetnodeqty{##1}}
+ \edef\snk@qtyii{\sankeygetnodeqty{##2}}
+ \ifdefstrequal{\snk@qtyi}{\snk@qtyii}{}{
\PackageError{sankey}%
- {^^J*** \string\sankeyoutin: quantities differ between ##2 (\sqty) and ##3 (\eqty)^^J}%
+ {^^J*** \string##3: quantities differ between %
+ ##1 (\snk@qtyi) and ##2 (\snk@qtyii)%
+ ^^J}%
{The quantities of the two Sankey nodes must be equal.}
}
+ \endgroup
+ }
+ \NewDocumentCommand\sankeydubins{O{}mm}{% options, sn, en
+ \snk@errorifnotdefined{##2}
+ \snk@errorifnotdefined{##3}
+ \snk@checkquantities{##2}{##3}{\sankeydubins}
+ \begingroup
+ \sankeyset{##1}
\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,
+ start point=##2.center,start angle=\sankeygetnodeorient{##2},
+ end point=##3.center,end angle=\sankeygetnodeorient{##3},
+ minimum radius=\snk@minradius + .5 * \sankeyqtytolen{\qty} pt,
},
}
\dubinspathcalc{sankey,store=sankey}
-
\dubinspathset{
left border/.style={
sankey, use store=sankey,
- left and right minimum radii=
- {\sankeyminradius} and {\sankeyminradius + \width pt},
+ left and right minimum radii={\snk@minradius}
+ and {\snk@minradius + \sankeyqtytolen{\qty} pt},
},
right border/.style={
sankey, use store=sankey,
left and right minimum radii=
- {\sankeyminradius + \width pt} and {\sankeyminradius},
+ {\snk@minradius + \sankeyqtytolen{\qty} pt}
+ and {\snk@minradius},
},
}
-
- \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}
- };
+ % fill the region
+ \path[/sankey/fill] (##2.left) \dubinspath{left border}
+ -- (##3.left) -- (##3.right) \dubinspath{right border,reverse}
+ -- (##2.right) -- cycle;
+ % draw left and right borders
+ \path[/sankey/draw] (##2.left) \dubinspath{left border}
+ (##2.right) \dubinspath{right border};
\endgroup
}
-
-
\NewDocumentCommand\sankeyoutin{O{}mm}{% options, sn, en
+ \snk@errorifnotdefined{##2}
+ \snk@errorifnotdefined{##3}
+ \snk@checkquantities{##2}{##3}{\sankeyoutin}
\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={
+ \edef\qty{\sankeygetnodeqty{##2}}
+ \pgfmathsetmacro\snk@len{\sankeyqtytolen{\qty}/2}
+ \edef\snk@step{\fpeval{1/\snk@stepoutin}}
+ \edef\snk@laststep{\inteval{\snk@stepoutin-1}}
+ \path[overlay,decorate,decoration={
markings,
- mark=between positions \mystep and \mybound step \mystep with {
- \def\sankeyoutinmidptname{sankeyoutinmidpt \pgfkeysvalueof{/pgf/decoration/mark info/sequence number}}
+ mark=between positions \snk@step and {\fpeval{1-.5*\snk@step}}
+ step \snk@step with {
+ \edef\snk@outinmidptname{%
+ snk@outinmidpt-%
+ \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)
+ (0,0) coordinate(\snk@outinmidptname)
+ (0,-\snk@len pt) coordinate (\snk@outinmidptname-r)
+ (0,\snk@len pt) coordinate (\snk@outinmidptname-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}
+ }]
+ (##2.center)
+ to[out=\sankeygetnodeorient{##2},in=\sankeygetnodeorient{##3}+180]
+ (##3.center);
+ \foreach \snk@ptnum in {1,...,\snk@laststep}{
+ \edef\snk@outinmidptname{snk@outinmidpt-\snk@ptnum}
+ \dbp@anglebetween\snk@outinmidptangle%
+ {\snk@outinmidptname-r}{\snk@outinmidptname-l}
+ \sankeynode[debug=false]{%
+ name=\snk@outinmidptname,
+ quantity=\qty,
+ angle=\snk@outinmidptangle-90,%
+ at=\snk@outinmidptname%
+ }
+ }
+ \sankeynode[debug=false]{%
+ name={snk@outinmidpt-0},
+ quantity=\sankeygetnodeqty{##2},
+ angle=\sankeygetnodeorient{##2},%
+ at={##2}%
+ }
+ \sankeynode[debug=false]{%
+ name={snk@outinmidpt-\snk@stepoutin},
+ quantity={\sankeygetnodeqty{##3}},
+ angle={\sankeygetnodeorient{##3}},%
+ at={##3}%
}
- \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)
+ (snk@outinmidpt-0.left)
+ \foreach \snk@curpt
+ [remember=\snk@curpt as \snk@prevpt (initially 0)]
+ in {1,...,\snk@stepoutin}{
+ to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt},
+ in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}+180]
+ (snk@outinmidpt-\snk@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)
+ (snk@outinmidpt-\snk@stepoutin.right)
+ \foreach \snk@curpt
+ [remember=\snk@curpt as \snk@prevpt (initially \snk@stepoutin)]
+ in {\snk@laststep,...,0}{
+ to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}+180,
+ in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}]
+ (snk@outinmidpt-\snk@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)
+ (snk@outinmidpt-0.left)
+ \foreach \snk@curpt
+ [remember=\snk@curpt as \snk@prevpt (initially 0)]
+ in {1,...,\snk@stepoutin}{
+ to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt},
+ in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}+180]
+ (snk@outinmidpt-\snk@curpt.left)
}
- ;
-
+ (snk@outinmidpt-\snk@stepoutin.right)
+ \foreach \snk@curpt
+ [remember=\snk@curpt as \snk@prevpt (initially \snk@stepoutin)]
+ in {\snk@laststep,...,0}{
+ to[out=\sankeygetnodeorient{snk@outinmidpt-\snk@prevpt}+180,
+ in=\sankeygetnodeorient{snk@outinmidpt-\snk@curpt}]
+ (snk@outinmidpt-\snk@curpt.right)
+ };
\endgroup
}
-
\NewDocumentCommand\sankeynodealias{mm}{%name, alias
- \path [late options={name=##1,alias=##2}];
- \sankeysetnodeqty{##2}{\sankeygetnodeqty{##1}}
- \sankeysetnodeorient{##2}{\sankeygetnodeorient{##1}}
+ \snk@errorifnotdefined{##1}
+ \path[late options={name=##1,alias=##2}];
+ \snk@setnodeqty{##2}{\sankeygetnodeqty{##1}}
+ \snk@setnodeorient{##2}{\sankeygetnodeorient{##1}}
}
-
- \newcommand\sankeynode[2][]{
+ \NewDocumentCommand\sankeynode{O{}m}{% options, node parameters
\begingroup
\sankeyset{##1}
- \sankeyset{node parameters,##2}
- %\typeout{sankeynode: '\name' at(\pos) angle(\orient) qty(\qty)}
- \sankeymakenode{}
+ \sankeyset{node parameters,@initial parameters,/sankey/every node,##2}
+ \snk@makenode{}
+ \snk@makeforkednode{}
+ \iftoggle{sankey node start}{\snk@filldrawstart}{}
+ \iftoggle{sankey node end}{\snk@filldrawend}{}
+ \snk@show@debug{\name}
\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}{
+ \NewDocumentCommand\sankeystart{O{}m}{% options, name
+ \snk@errorifnotdefined{##2}
\begingroup
\sankeyset{##1}
\edef\name{##2}
\edef\orient{\sankeygetnodeorient{##2}}
\edef\qty{\sankeygetnodeqty{##2}}
- \sankeyfilldrawstart
+ \snk@filldrawstart
\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
+ \NewDocumentCommand\sankeynodestart{O{}m}{% option, node parameters
+ \sankeynode[##1]{start,##2}
}
-
- \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
+ \NewDocumentCommand\sankeyend{O{}m}{%options, name
+ \snk@errorifnotdefined{##2}
\begingroup
\sankeyset{##1}
\edef\name{##2}
\edef\orient{\sankeygetnodeorient{##2}}
\edef\qty{\sankeygetnodeqty{##2}}
- \sankeyfilldrawend
+ \snk@filldrawend
\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\sankeynodeend{O{}m}{% options, node parameters
+ \sankeynode[##1]{end,##2}
}
-
-
-
- \NewDocumentCommand\sankeyadvance{sO{}mm}{% *(reverse), options, name, distance
+ \NewDocumentCommand\sankeyadvance{sO{}mm}{%
+ %params: *(reverse), options, name, distance
+ \snk@errorifnotdefined{##3}
\begingroup
\sankeyset{##2}
- \def\newname{##3}
- \def\oldname{##3-old}
- \sankeynodealias{\newname}{\oldname}
- % \typeout{*** sankeyadvance: ok (\oldname => \newname)}
+ \edef\name{##3}
+ \edef\snk@oldname{##3-old}
+ \sankeynodealias{\name}{\snk@oldname}
\IfBooleanTF{##1}{
- % reverse advance
+ % move backward
\sankeynode{
- at={$(\oldname.center)!##4!90:(\oldname.left)$},
- angle=\sankeygetnodeorient{\oldname},
- quantity=\sankeygetnodeqty{\oldname},
- name=\newname,
+ at={$(\snk@oldname.center)!##4!90:(\snk@oldname.left)$},
+ angle=\sankeygetnodeorient{\snk@oldname},
+ quantity=\sankeygetnodeqty{\snk@oldname},
+ name=\name,
}
\path[/sankey/fill]
- (\newname.left) -- (\oldname.left)
- --
- (\oldname.right) -- (\newname.right)
- -- cycle;
+ (\name.left) -- (\snk@oldname.left)
+ -- (\snk@oldname.right) -- (\name.right) -- cycle;
\path[/sankey/draw]
- (\newname.left) -- (\oldname.left)
- (\oldname.right) -- (\newname.right);
- \endgroup
+ (\name.left) -- (\snk@oldname.left)
+ (\snk@oldname.right) -- (\name.right);
}{
- % advance
+ % move forward
\sankeynode{
- at={$(\oldname.center)!##4!-90:(\oldname.left)$},
- angle=\sankeygetnodeorient{\oldname},
- quantity=\sankeygetnodeqty{\oldname},
- name=\newname,
+ at={$(\snk@oldname.center)!##4!-90:(\snk@oldname.left)$},
+ angle=\sankeygetnodeorient{\snk@oldname},
+ quantity=\sankeygetnodeqty{\snk@oldname},
+ name=\name,
}
\path[/sankey/fill]
- (\oldname.left) -- (\newname.left)
- --
- (\newname.right) -- (\oldname.right)
- -- cycle;
+ (\snk@oldname.left) -- (\name.left)
+ -- (\name.right) -- (\snk@oldname.right) -- cycle;
\path[/sankey/draw]
- (\oldname.left) -- (\newname.left)
- (\newname.right) -- (\oldname.right);
- \endgroup
+ (\snk@oldname.left) -- (\name.left)
+ (\name.right) -- (\snk@oldname.right);
}
+ \snk@show@debug{\name}
+ \endgroup
}
-
- \NewDocumentCommand\sankeyturn{sO{}mm}{% *(reverse), options, name, angle
+ \NewDocumentCommand\sankeyturnright{sO{}mm}{
+ % *(reverse), options, name, angle
+ \snk@errorifnotdefined{##3}
\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}
- };
- }
+ \IfBooleanTF{##1}
+ {\edef\snk@angle{\fpeval{-1*##4}}}
+ {\edef\snk@angle{\fpeval{1*##4}}}
+ \edef\snk@anglesign{\fpeval{sign(\snk@angle)}}
+ \ifnumgreater{\snk@anglesign}{-1}{
+ \sankeyset{##2}
+ \edef\name{##3}
+ \edef\snk@oldname{##3-old}
+ \sankeynodealias{\name}{\snk@oldname}
+ \edef\qty{\sankeygetnodeqty{\name}}
+ \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}-\snk@angle}}
+ \snk@getpos\snk@c{$(\name.right)!-\snk@minradius!(\name.left)$}
+ \snk@getpos\pos{$(\snk@c)!1!-\snk@angle:(\name.center)$}
+ \snk@makenode{}
+ % fill the region
+ \path[/sankey/fill] let
+ \p1=(\snk@oldname.left),\p2=(\snk@oldname.right),
+ \p3=(\name.left),\p4=(\name.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1},
+ \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient+\snk@angle+90:\orient+90:\n{maxr}) -- (\p3) --
+ (\p4) arc(\orient+90:\orient+\snk@angle+90:\n{minr}) -- (\p2) -- cycle;
+ % draw left and right borders
+ \path[/sankey/draw] let
+ \p1=(\snk@oldname.left),\p2=(\snk@oldname.right),
+ \p3=(\name.left),\p4=(\name.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1},
+ \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient+\snk@angle+90:\orient+90:\n{maxr})
+ (\p4) arc(\orient+90:\orient+\snk@angle+90:\n{minr});
+ \snk@show@debug{\name}
}{
- % 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}
- };
- }
+ \sankeyturnrightbackward[##2]{##3}{-1*\snk@angle}
}
\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}
- };
+ \NewDocumentCommand\sankeyturnrightbackward{sO{}mm}{
+ % *(reverse), options, name, angle
+ \snk@errorifnotdefined{##3}
+ \begingroup
+ \IfBooleanTF{##1}
+ {\edef\snk@angle{\fpeval{-1*##4}}}
+ {\edef\snk@angle{\fpeval{1*##4}}}
+ \edef\snk@anglesign{\fpeval{sign(\snk@angle)}}
+ \ifnumgreater{\snk@anglesign}{-1}{
+ \sankeyset{##2}
+ \edef\name{##3}
+ \edef\snk@oldname{##3-old}
+ \sankeynodealias{\name}{\snk@oldname}
+ \edef\qty{\sankeygetnodeqty{\name}}
+ \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}+\snk@angle}}
+ \snk@getpos\snk@c{$(\name.right)!-\snk@minradius!(\name.left)$}
+ \snk@getpos\pos{$(\snk@c)!1!\snk@angle:(\name.center)$}
+ \snk@makenode{}
+ % fill the region
+ \path[/sankey/fill] let
+ \p1=(\name.left),\p2=(\name.right),
+ \p3=(\snk@oldname.left),\p4=(\snk@oldname.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient+90:\orient-\snk@angle+90:\n{maxr}) -- (\p3) --
+ (\p4) arc(\orient-\snk@angle+90:\orient+90:\n{minr}) -- (\p2) -- cycle;
+ % draw left and right borders
+ \path[/sankey/draw] let
+ \p1=(\name.left),\p2=(\name.right),
+ \p3=(\snk@oldname.left),\p4=(\snk@oldname.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient+90:\orient-\snk@angle+90:\n{maxr})
+ (\p4) arc(\orient-\snk@angle+90:\orient+90:\n{minr});
+ \snk@show@debug{\name}
+ }{
+ \sankeyturnright[##2]{##3}{-1*\snk@angle}
}
- \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}
+ \endgroup
+ }
+ \NewDocumentCommand\sankeyturnleft{sO{}mm}{
+ % *(reverse), options, name, angle
+ \snk@errorifnotdefined{##3}
+ \begingroup
+ \IfBooleanTF{##1}
+ {\edef\snk@angle{\fpeval{-1*##4}}}
+ {\edef\snk@angle{\fpeval{1*##4}}}
+ \edef\snk@anglesign{\fpeval{sign(\snk@angle)}}
+ \ifnumgreater{\snk@anglesign}{-1}{
+ \sankeyset{##2}
+ \edef\name{##3}
+ \edef\snk@oldname{##3-old}
+ \sankeynodealias{\name}{\snk@oldname}
+ \edef\qty{\sankeygetnodeqty{\name}}
+ \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}+\snk@angle}}
+ \snk@getpos\snk@c{$(\name.left)!-\snk@minradius!(\name.right)$}
+ \snk@getpos\pos{$(\snk@c)!1!\snk@angle:(\name.center)$}
+ \snk@makenode{}
+ % fill the region
+ \path[/sankey/fill] let
+ \p1=(\snk@oldname.left),\p2=(\snk@oldname.right),
+ \p3=(\name.left),\p4=(\name.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient-\snk@angle-90:\orient-90:\n{minr}) -- (\p3) --
+ (\p4) arc(\orient-90:\orient-\snk@angle-90:\n{maxr}) -- (\p2) -- cycle;
+ % draw left and right borders
+ \path[/sankey/draw] let
+ \p1=(\snk@oldname.left),\p2=(\snk@oldname.right),
+ \p3=(\name.left),\p4=(\name.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient-\snk@angle-90:\orient-90:\n{minr})
+ (\p4) arc(\orient-90:\orient-\snk@angle-90:\n{maxr});
+ \snk@show@debug{\name}
+ }{
+ \sankeyturnleftbackward[##2]{##3}{-1*\snk@angle}
}
+ \endgroup
}
-
- \def\sankeyqtytolen##1{\fpeval{(##1)/\sankeytotalqty*\sankeytotallen}}
-
+ \NewDocumentCommand\sankeyturnleftbackward{sO{}mm}{
+ % *(reverse), options, name, angle
+ \snk@errorifnotdefined{##3}
+ \begingroup
+ \IfBooleanTF{##1}
+ {\edef\snk@angle{\fpeval{-1*##4}}}
+ {\edef\snk@angle{\fpeval{1*##4}}}
+ \edef\snk@anglesign{\fpeval{sign(\snk@angle)}}
+ \ifnumgreater{\snk@anglesign}{-1}{
+ \sankeyset{##2}
+ \edef\name{##3}
+ \edef\snk@oldname{##3-old}
+ \sankeynodealias{\name}{\snk@oldname}
+ \edef\qty{\sankeygetnodeqty{\name}}
+ \edef\orient{\snk@normalize@angle{\sankeygetnodeorient{\name}-\snk@angle}}
+ \snk@getpos\snk@c{$(\name.left)!-\snk@minradius!(\name.right)$}
+ \snk@getpos\pos{$(\snk@c)!1!-\snk@angle:(\name.center)$}
+ \snk@makenode{}
+ % fill the region
+ \path[/sankey/fill] let
+ \p1=(\name.left),\p2=(\name.right),
+ \p3=(\snk@oldname.left),\p4=(\snk@oldname.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient-90:\orient+\snk@angle-90:\n{minr}) -- (\p3) --
+ (\p4) arc(\orient+\snk@angle-90:\orient-90:\n{maxr}) -- (\p2) -- cycle;
+ % draw left and right borders
+ \path[/sankey/draw] let
+ \p1=(\name.left),\p2=(\name.right),
+ \p3=(\snk@oldname.left),\p4=(\snk@oldname.right),
+ \n1={\sankeyqtytolen{\qty}},
+ \n{maxr}={\snk@minradius+\n1}, \n{minr}={\snk@minradius}
+ in
+ (\p1) arc(\orient-90:\orient+\snk@angle-90:\n{minr})
+ (\p4) arc(\orient+\snk@angle-90:\orient-90:\n{maxr});
+ \snk@show@debug{\name}
+ }{
+ \sankeyturnleft[##2]{##3}{-1*\snk@angle}
+ }
+ \endgroup
+ }
+ \NewDocumentCommand\sankeyturn{sO{}mm}{%
+ % *(reverse), options, name, angle
+ \snk@errorifnotdefined{##3}
+ \begingroup
+ \edef\snk@anglesign{\fpeval{sign(##4)}}
+ \IfBooleanTF{##1}{
+ \ifnumgreater{\snk@anglesign}{-1}
+ {\sankeyturnleftbackward[##2]{##3}{##4}}
+ {\sankeyturnrightbackward[##2]{##3}{-1*##4}}
+ }{
+ \ifnumgreater{\snk@anglesign}{-1}
+ {\sankeyturnleft[##2]{##3}{##4}}
+ {\sankeyturnright[##2]{##3}{-1*##4}}
+ }
+ \endgroup
+ }
+ \NewDocumentCommand\sankeyfork{O{}mm}{%options, name, list of forks
+ \snk@errorifnotdefined{##2}
+ \begingroup
+ \sankeyset{##1}
+ \sankeynode[debug=false]{as={##2},forked={##3}}
+ \foreach \qty/\snk@subnodename in {##3}{\sankeynode{as={\snk@subnodename}}}
+ \endgroup
+ }
+ \def\sankeyqtytolen##1{\fpeval{(##1)/\snk@totalqty*\snk@totallen}}
\sankeyset{
- % % default values,
- % /tikz/declare function={
- % % sankeyqtytolen(\qty)=\qty/\sankeytotalqty*\sankeytotallen;
- % % sankeylentoqty(\len)=\len/\sankeytotallen*\sankeytotalqty;
- % },%
- default parameters,%
+ @initial options,
+ every diagram,
% user values
#1}
-
- %\typeout{sankeytotallen: \sankeytotallen}
-
- #2 % body of sankeydiagram environment
}
-
-
+{} % empty but mandatory ! :-)
\sankeyset{
- % none style
new start style={none}{}{},
new end style={none}{}{},
- % simple style
+}
+\sankeyset{
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) -- cycle
}{
- (\name.left) -- ([xshift=-.5\pgflinewidth]\name.left) -- ([xshift=-.5\pgflinewidth]\name.right) -- (\name.right)
+ (\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) -- cycle
}{
- (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right)
+ (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right)
},
- % arrow style
+}
+\sankeyset{
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) -- cycle
}{
- (\name.left) -- ++(-10pt,0)
- -- ([xshift=-10pt/6]\name.center)
- -- ([xshift=-10pt]\name.right)
- -- (\name.right)
+ (\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
+ -- ([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)
+ -- ([xshift=10pt]\name.center) -- ([yshift=-1mm]\name.right)
+ -- (\name.right)
},
-} \ No newline at end of file
+}
+\endinput
+%%
+%% End of file `sankey.sty'.