diff options
author | Karl Berry <karl@freefriends.org> | 2021-03-14 23:19:59 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-03-14 23:19:59 +0000 |
commit | ceca438fddde2040f41fc0723fc066a8345f5e2b (patch) | |
tree | 67b1de096b693347b60a6308446e3b2e02ff6c1e /Master/texmf-dist/source | |
parent | ce7d08a8d4a8e445cae634dce76820b4a81485d6 (diff) |
sankey (14mar21) (branch)
git-svn-id: svn://tug.org/texlive/branches/branch2020.0@58363 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source')
-rw-r--r-- | Master/texmf-dist/source/latex/sankey/sankey.dtx | 4678 | ||||
-rw-r--r-- | Master/texmf-dist/source/latex/sankey/sankey.ins | 85 |
2 files changed, 4763 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/sankey/sankey.dtx b/Master/texmf-dist/source/latex/sankey/sankey.dtx new file mode 100644 index 00000000000..451472c5b27 --- /dev/null +++ b/Master/texmf-dist/source/latex/sankey/sankey.dtx @@ -0,0 +1,4678 @@ +% \iffalse meta-comment +% +% 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 +% +% +% \fi +% +% \iffalse +% +%<*driver> +\documentclass[a4paper,10pt,draft]{ltxdoc} +\usepackage{sankey-doc-preamble} +\EnableCrossrefs +\CodelineIndex +\RecordChanges +\begin{document} +\DocInput{sankey.dtx} +\end{document} +%</driver> +% \fi +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \CheckSum{1718} +% +% +% \GetFileInfo{\jobname.dtx} +% +% \DoNotIndex{\newcommand,\newenvironment} +% \DoNotIndex{\#,\$,\%,\&,\@,\\,\{,\},\^,\_,\~,\ } +% \DoNotIndex{\begingroup,\endgroup,\begin,\end} +% \DoNotIndex{\def,\edef,\gdef,\xdef,\ifx,\else,\string,\relax} +% \DoNotIndex{\csname,\endcsname,\ifcsdef,\expandafter,\ifnumgreater} +% \DoNotIndex{\NewDocumentCommand,\NewDocumentEnvironment,\IfBooleanTF} +% \DoNotIndex{\NeedsTeXFormat,\ProvidesPackage,\RequirePackage,\PackageError,\PackageWarning} +% \DoNotIndex{\newtoggle,\toggletrue,\togglefalse,\iftoggle,\ifdefempty,\ifundef,\ifdefstrequal} +% \DoNotIndex{\ifbool,\ifdef,\ifnumequal,\ifpgfmathcond,\colorlet,\fpeval,\inteval,\newbool} +% \DoNotIndex{\pgfmathsetmacro,\pgfdeclarelayer,\pgfdeclareshape,\pgfkeys,\pgfset,\usetikzlibrary} +% \DoNotIndex{\the,\pgf@x,\pgf@y,\tikz@scan@one@point,\pgfutil@firstofone} +% \DoNotIndex{\pgfsetlayers,\inheritsavedanchors,\inheritanchor,\inheritanchorborder,\anchor,\pgf@process,\northeast,\southwest} +% \DoNotIndex{\pgfmathresult,\pgfinterruptpath,\endpgfinterruptpath,\pgfkeysvalueof,\pgfmathtruncatemacro,\pgfmathparse} +% \DoNotIndex{\tikzset,\pgfextra,\pgflinewidth,\foreach,\coordinate} +% \DoNotIndex{\path,\node,\pgfmathprintnumber,\n,\p,\x,\y} +% \DoNotIndex{\tiny,\ttfamily,\space} +% +% \title{The \textsf{sankey} package\\ +% Draw Sankey diagrams via TikZ} +% +% \author{Paul Gaborit +% (\href{mailto:paul.gaborit@gmail.com}{\texttt{paul.gaborit@gmail.com}})} +% \date{\fileversion{} -- \filedate{}} +% +% \GetFileInfo{sankey.sty} +% +% \def\manualparts{ +% \begin{quote} +% This manual contains three parts: +% \nameref{usermanual} (p.\pageref{usermanual}), +% \nameref{examples} (p.\pageref{examples}) +% and \nameref{implementation} (p.\pageref{implementation}). +% \end{quote} +% } +% +% \maketitle +% +% \hypersetup{ +% pdftitle=How to use the sankey package to build Sankey diagrams (\fileversion), +% pdfauthor=Paul Gaborit, +% } +% +% +% +% \begin{abstract} +% The \texttt{sankey} package provides macros and environments to +% build \emph{Sankey +% diagrams}\footnote{\url{https://en.wikipedia.org/wiki/Sankey_diagram}}, +% i.e. \emph{flow diagrams} in which the width of the arrows is +% proportional to the flow rate. The initial idea for the first +% implementation came out from +% \href{https://tex.stackexchange.com/q/40159/14500}{this question} on +% \href{https://tex.stackexchange.com/}{TeX.StackExchange}. +% +% +% \end{abstract} +% +% \manualparts +% +% \begin{quote} +% {\footnotesize Note: the \code{sankey.dtx} and \code{sankey.ins} +% files are attachments of the current PDF document.\par} +% \end{quote} +% +%^^A % ------------------------------------------------------------ +% \part{User manual} +% \label{usermanual} +%^^A % ------------------------------------------------------------ +% +% { +% \setlength{\parskip}{0pt} +% \localtableofcontents +% } +% +%^^A % ------------------------------------------------------------ +% \section{Preamble} +%^^A % ------------------------------------------------------------ +% +% To use the \code{sankey} package, insert the following line in your preamble: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \usepackage{sankey} +% \end{lstlisting} +% +% {\small Note: the +% \code{sankey} package requires automatically the +% \code{xparse}, \code{etoolbox}, \code{xfp} and +% \code{tikz} packages, and the \code{calc}, +% \code{decorations.markings} and +% \code{dubins} (cf. \vref{sec:dubins}) TikZ libraries.\par} +% +% +%^^A % ------------------------------------------------------------ +% \section{The \texttt{sankeydiagram} environment} +%^^A % ------------------------------------------------------------ +% +% \DescribeEnv{sankeydiagram} % +% A \code{sankeydiagram} environment nested in a \code{tikzpicture} +% environment activates the sankey macros: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \begin{tikzpicture} +% \begin{sankeydiagram}[... options ...] +% ... sankey macros ... +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{lstlisting} +% +%^^A % ------------------------------------------------------------ +% \section{Sankey diagram options} +%^^A % ------------------------------------------------------------ +% +% The \code{sankey} package uses \code{pgfkeys} to set options via +% \emph{key=value} pairs with default path \texttt{/sankey} (and +% \texttt{/sankey/node parameters} for Sankey node parameters). +% +% The options can be defined via the optional argument of the +% \code{sankeydiagram} environment: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \begin{sankeydiagram}[debug=true] +% \sankeynode{name=a,quantity=1,angle=0,at={0,0}} +% \end{sankeydiagram} +% \end{lstlisting} +% +% \DescribeMacro{\sankeyset} % +% The options can also be modified via the \code{\sankeyset} macro: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \begin{sankeydiagram} +% \sankeyset{debug=true} +% \sankeynode{name=a,quantity=1,angle=0,at={0,0}} +% \end{sankeydiagram} +% \end{lstlisting} +% +% The options can be temporarily modified for a single macro: +% \begin{lstlisting}[style=LaTeXsmall] +% \begin{sankeydiagram} +% \sankeynode[debug=true]{name=a,quantity=1,angle=0,at={0,0}} +% \end{sankeydiagram} +% \end{lstlisting} +% +% At the begining of each Sankey diagram, all options are initialized +% with initial values then the \code{every diagram} style is applied. +% +% \begin{sankeyoption}{every diagram}{}{}{empty} +% This style is installed at beginning of each Sankey diagram. +% \end{sankeyoption} +% +% For instance, to use a ratio of 5mm/10 by default (instead of 1cm/10) +% for all Sankey diagrams, add the following line: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \sankeyset{every diagram/.style={ratio=5mm/10}} +% \end{lstlisting} +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys to choose the scale} +%^^A % ------------------------------------------------------------ +% +% The scale or ratio of the Sankey diagram is the ratio between the % +% \code{ratio length} and the \code{ratio quantity}. +% +% \begin{sankeyoption}{ratio quantity}{\VAR{number}}{}{10} +% Quantity (in units of flow) to define ratio. The \VAR{number} can be +% any math expression. +% \end{sankeyoption} +% +% \begin{sankeyoption}{ratio length}{\VAR{distance}}{}{1cm} +% Distance (a graphical distance) to define scale. +% \end{sankeyoption} +% +% \begin{sankeyoption}{ratio}{\VAR{distance}/\VAR{number}}{}{1cm/10} +% Fix the ratio to \VAR{distance}\texttt{/}\VAR{number}. +% \end{sankeyoption} +% +% The initial ratio is 1\,cm/10 units. +% +% +% \textbf{Note:} the \code{sankey} package uses the \code{xfp} package to +% evaluate all math expressions that use quantities (in units of +% flow). You can therefore use quantities of a very large or very small +% order of magnitude. In contrast, for graphic distances, the sankey +% package uses the \code{pgfmath} package (all calculations must not +% exceed $\pm 16383.99999$). +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys to define rotate offset} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{rotate}{\VAR{angle}}{}{0} +% +% The \code{rotate} key stores an offset angle applied to all Sankey +% nodes. This is useful when using the \code{rotate} option within a +% \code{tikzpicture} or a \code{scope}. This TikZ option is only +% applied to coordinates and not to TikZ nodes (remember that Sankey +% nodes are TikZ nodes). It's up to the author to keep the +% \code{rotate} option of the \code{tikzpicture} and that of the +% \code{sankeydiagram} synchronous. +% +% \end{sankeyoption} +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys to define drawing parameters} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{minimum radius}{\VAR{distance}}{}{5mm} +% The minimum radius used by \code{\sankeyturn} and +% \code{\sankeydubins}. +% \end{sankeyoption} +% +% \begin{sankeyoption}{outin steps}{\VAR{integer}}{}{10} +% Number of steps used by the \code{\sankeyoutin} macro to simulate flow +% lanes with constant width. +% \end{sankeyoption} +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys to choose drawing styles} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{fill/.style}{\VAR{style}}{}{{line width=0pt,fill=white}} +% This TikZ style is used to \emph{fill} all sankey paths. +% \end{sankeyoption} +% +% \begin{sankeyoption}{draw/.style}{\VAR{style}}{}{draw=black,line width=.4pt} +% This TikZ style is used to \emph{draw} all sankey paths. +% \end{sankeyoption} +% +% \begin{sankeyoption}{start style}{\VAR{style name}}{}{none} +% There are three predefined \emph{start} styles: \constant{none}, +% \constant{simple}, \constant{arrow}. +% \end{sankeyoption} +% +% \begin{sankeyoption}{end style}{\VAR{style name}}{}{none} +% There are three predefined \emph{end} styles: \constant{none}, +% \constant{simple}, \constant{arrow}. +% \end{sankeyoption} +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys to define new \emph{start} and \emph{end} styles} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{new start style}{\{\VAR{name}\}\{\VAR{fill +% path}\}\{\VAR{draw path}\}}{}{} +% Define the new start style named \VAR{name} with its \VAR{fill +% path} and its \VAR{draw path}. +% \end{sankeyoption} +% +% \begin{sankeyoption}{new end style}{\{\VAR{name}\}\{\VAR{fill +% path}\}\{\VAR{draw path}\}}{}{} +% Define the new end style named \VAR{name} with its \VAR{fill +% path} and its \VAR{draw path}. +% \end{sankeyoption} +% +% \emph{Fill} and \emph{draw} paths are build in a TikZ scope where the +% origin is the center of the current Sankey node (its name is accessible +% via \code{\name}) and the coordinate system is rotated by its +% orientation. +% +%^^A % ------------------------------------------------------------ +% \subsection{The \emph{debug} key} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{debug}{\VAR{boolean}}{true}{false} +% To debug a sankey diagram. +% \end{sankeyoption} +% +%^^A % ------------------------------------------------------------ +% \section{Sankey nodes and flows} +%^^A % ------------------------------------------------------------ +% +%^^A % ------------------------------------------------------------ +% \subsection{Create Sankey nodes} +%^^A % ------------------------------------------------------------ +% +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \MACRO\code{\sankeynode}\OPTARG{\VAR{options}}\ARG{\VAR{node parameters}} +% +% \DescribeMacro{\sankeynode} % +% The \code{\sankeynode} macro defines a Sankey node. The \VAR{options} +% can be any Sankey diagram keys. To define a Sankey node, you must +% provide a \emph{name}, a \emph{quantity} and an \emph{angle} as +% \VAR{node parameters}. +% +% \begin{sankeyoption}[/sankey/node parameters]{name}{\VAR{name}}{}{} +% The \VAR{name} of the new Sankey node (and the associated TikZ node). +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{quantity}{\VAR{quantity}}{}{} +% The quantity (in flow unit) of the new Sankey node. The \VAR{quantity} +% can be any math expression. +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{angle}{\VAR{angle}}{}{} +% The orientation of the flow (0 points to the right) of the new Sankey +% node. +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{at}{\VAR{at}}{}{0,0} +% The position of the new Sankey node (a TikZ coordinate \emph{without} +% round brackets or parentheses). +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{anchor}{\VAR{anchor}}{}{center} +% Specify the anchor of the Sankey node. Possible values are +% \constant{center}, \constant{left} or \constant{right}. +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{as}{\VAR{name}}{}{} +% Copy the \emph{name}, the \emph{quantity}, the \emph{angle} and the +% \emph{position} of the Sankey node named \VAR{name}. +% \end{sankeyoption} +% +% A Sankey node is also a Tikz node but with only three anchors: +% \code{left}, \code{center} and \code{right}\footnote{In fact, to be +% able to use the TikZ \code{fit} library, the % +% \code{north}, \code{north east} and \code{north west} anchors exist +% and are equal to \code{left}, % +% the \code{east} and \code{west} anchors exist and are equal to +% \code{center} and % +% the \code{south}, \code{south east} and \code{south west} anchors +% exist and are equal to \code{right}.}: +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[debug] +% \sankeynode{name=a,quantity=10} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right} +% +% \foreach \nodename/\pos in {a/left,b/below left,c/above}{ +% \foreach \ancname in {left,center,right}{ +% \node[node font=\ttfamily\footnotesize,\pos=1mm of \nodename.\ancname, +% inner sep=0pt,rotate=\sankeygetnodeorient{\nodename},anchor=east] +% {\ancname\vphantom{g}}; +% \fill[black] (\nodename.\ancname) circle(1pt); +% } +% } +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +%^^A % ------------------------------------------------------------ +% \subsubsection{Choose default parameters} +%^^A % ------------------------------------------------------------ +% +% \begin{sankeyoption}{every node/.style}{\{\VAR{node parameters}\}}{}{empty} +% The \VAR{node parameters} defined by the +% \code{every node} style is installed at the creation of every Sankey node. +% \end{sankeyoption} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Create starting and ending nodes via macros} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \MACRO\code{\sankeynodestart}\OPTARG{\VAR{options}}\ARG{\VAR{node parameters}} +% +% \DescribeMacro{\sankeynodestart} % +% The \code{\sankeynodestart} creates and fills/draws a starting Sankey +% node: +% +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] +% \sankeynodestart{name=a,quantity=10} +% \sankeynodestart{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeynodestart{name=c,quantity=20,angle=-90,at={5,1},anchor=right} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +%^^A % ------------------------------------------------------------ +% +% +% \begin{miniblock} +% \MACRO\code{\sankeynodeend}\OPTARG{\VAR{options}}\ARG{\VAR{node +% parameters}} +% +% \DescribeMacro{\sankeynodeend} % +% The \code{\sankeynodeend} creates and fills/draws an ending Sankey +% node: +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[end style=simple,fill/.style={fill=orange!20}] +% \sankeynodeend{name=a,quantity=10} +% \sankeynodeend{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeynodeend{name=c,quantity=20,angle=-90,at={5,1},anchor=right} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Create starting and ending nodes via options} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \begin{sankeyoption}[/sankey/node parameters]{start}{\VAR{boolean}}{true}{false} +% The \code{\sankeynode} macro acts as the +% \code{\sankeynodestart} macro if you add the +% \code{start} option to its options. +% \end{sankeyoption} +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] +% \sankeynode{name=a,quantity=10,start} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left,start} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right,start} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \begin{sankeyoption}[/sankey/node parameters]{end}{\VAR{boolean}}{true}{false} +% The \code{\sankeynode} macro acts as the \code{\sankeynodeend} +% macro if you add the \code{end} option to its options. +% \end{sankeyoption} +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[end style=simple,fill/.style={fill=orange!20}] +% \sankeynode{name=a,quantity=10,end} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left,end} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right,end} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% +% \begin{miniblock} +% Although rarely necessary, you can mix these two parameters: +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram} +% \sankeyset{ +% end style=arrow, +% start style=arrow, +% fill/.style={fill=orange!20} +% } +% \sankeynode{name=a,quantity=10,start,end} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left,start,end} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right,start,end} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsection{Retrieve information from Sankey nodes} +%^^A % ------------------------------------------------------------ +% +% \MACRO\code{\sankeygetnodeqty}\ARG{\VAR{node name}} +% +% \DescribeMacro{\sankeygetnodeqty} % +% The expandable command \code{\sankeygetnodeqty} returns the quantity +% assigned to the Sankey node named \VAR{node name}. +% +% \MACRO\code{\sankeyqtytolen}\ARG{\VAR{quantity}} +% +% \DescribeMacro{\sankeyqtytolen} % +% The expandable \code{\sankeyqtytolen} macro converts \VAR{quantity} to +% graphical length using the current ratio. +% +% \MACRO\code{\sankeygetnodeorient}\ARG{\VAR{node name}} +% +% \DescribeMacro{\sankeygetnodeorient} % +% The expandable command \code{\sankeygetnodeorient} returns the angle +% (orientation) assigned to the Sankey node named \VAR{node name}. +% +%^^A % ------------------------------------------------------------ +% \subsection{Move nodes} +%^^A % ------------------------------------------------------------ +% +% All the macros of this section move a Sankey node and fill/draw a +% portion of the Sankey flow. Then the previous position of the Sankey +% node is accessible via the \code{-old} suffix (i.e. if you move the +% \code{a} node, its previous position is the \code{a-old} node). +% +% The starred version of each of these macros moves in the opposite +% direction to their non-starred version. +% +% Except for the \code{\sankeyturn} macro, a negative value (distance or +% angle) moves in the opposite direction (the \code{\sankeyturn} macro +% is an exception: a negative angle turns right while a positive value +% turns left). +% +% {\centering +% \begin{tikzpicture} +% \begin{sankeydiagram} +% \tikzset{com/.style={node font=\ttfamily\scriptsize, +% fill=bgcode,fill opacity=1,text opacity=1}} +% \sankeyset{end style=simple,start style=simple} +% \sankeynode{name=ac,quantity=5} +% \sankeynode{name=al,quantity=5,at={[yshift=2mm]ac.left},anchor=right} +% \sankeynode{name=ar,quantity=5,at={[yshift=-2mm]ac.right},anchor=left} +% \sankeyturnleft{al}{60} +% \sankeyadvance{ac}{1cm} +% \sankeyturnright{ar}{60} +% \sankeyturnleft*{al-old}{60} +% \sankeyadvance*{ac-old}{1cm} +% \sankeyturnright*{ar-old}{60} +% \sankeystart{al-old} +% \sankeystart{ac-old} +% \sankeystart{ar-old} +% \sankeyend{al} +% \sankeyend{ac} +% \sankeyend{ar} +% \draw[red,very thick] +% (al-old-old.left) -- node[com]{n} (al-old-old.right) +% (ac-old-old.left) -- node[com]{n} (ac-old-old.right) +% (ar-old-old.left) -- node[com]{n} (ar-old-old.right); +% \path +% (al) ++(2mm,2mm) node[com,anchor=south west,align=left] { +% \string\sankeyturnleft\{n\}\{angle>0\}\\ +% \string\sankeyturnleftbackward\{n\}\{angle<0\}\\ +% \string\sankeyturnleft*\{n\}\{angle<0\}\\ +% \string\sankeyturnleftbackward*\{n\}\{angle>0\}\\ +% \string\sankeyturn\{n\}\{angle>0\} +% }; +% \path +% (al-old) ++(-2mm,2mm) node[com,anchor=south east,align=right] { +% \string\sankeyturnleftbackward\{n\}\{angle>0\}\\ +% \string\sankeyturnleft\{n\}\{angle<0\}\\ +% \string\sankeyturnleft*\{n\}\{angle>0\}\\ +% \string\sankeyturnleftbackward*\{n\}\{angle<0\}\\ +% \string\sankeyturn*\{n\}\{angle>0\} +% }; +% \path +% (ac) ++(2mm,0) node[com,anchor=west,align=left] { +% \string\sankeyadvance\{n\}\{distance>0\}\\ +% \string\sankeyadvance*\{n\}\{distance<0\} +% }; +% \path +% (ac-old) ++(-2mm,0) node[com,anchor=east,align=right] { +% \string\sankeyadvance\{n\}\{distance<0\}\\ +% \string\sankeyadvance*\{n\}\{distance>0\} +% }; +% \path +% (ar) ++(2mm,-2mm) node[com,anchor=north west,align=left] { +% \string\sankeyturnright\{n\}\{angle>0\}\\ +% \string\sankeyturnrightbackward\{n\}\{angle<0\}\\ +% \string\sankeyturnright*\{n\}\{angle<0\}\\ +% \string\sankeyturnrightbackward*\{n\}\{angle>0\}\\ +% \string\sankeyturn\{n\}\{angle<0\} +% }; +% \path +% (ar-old) ++(-2mm,-2mm) node[com,anchor=north east,align=right] { +% \string\sankeyturnrightbackward\{n\}\{angle>0\}\\ +% \string\sankeyturnright\{n\}\{angle<0\}\\ +% \string\sankeyturnright*\{n\}\{angle>0\}\\ +% \string\sankeyturnrightbackward*\{n\}\{angle<0\}\\ +% \string\sankeyturn*\{n\}\{angle<0\} +% }; +% \end{sankeydiagram} +% \end{tikzpicture} +% \par} +%^^A % ------------------------------------------------------------ +% \subsubsection{Macro to move straight (forward or backward)} +%^^A % ------------------------------------------------------------ +% +% +% \begin{miniblock} +% \MACRO\code{\sankeyadvance}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{distance}} +% +% \DescribeMacro{\sankeyadvance} The \code{\sankeyadvance} moves the +% sankey node straight ahead and fills/draws this portion of the +% sankey path. A positive \VAR{distance} moves forward while a +% negative \VAR{distance} moves backward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] +% \sankeynodestart{name=a,quantity=10} +% \sankeyadvance{a}{1cm} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeynodestart{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyadvance{b}{1cm} +% \sankeynodestart{name=c,quantity=10,angle=-90,at={5,1},anchor=right} +% \sankeyadvance{c}{5mm} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyadvance*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{distance}} +% +% \DescribeMacro{\sankeyadvance*} The \code{\sankeyadvance*} moves +% the sankey node straight back and fills/draws this portion of the +% sankey path. A positive \VAR{distance} moves backward while a +% negative \VAR{distance} moves forward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[end style=arrow,fill/.style={fill=orange!20}] +% \sankeynodeend{name=a,quantity=10} +% \sankeyadvance*{a}{1cm} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeynodeend{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyadvance*{b}{1cm} +% \sankeynodeend{name=c,quantity=10,angle=-90,at={5,1},anchor=right} +% \sankeyadvance*{c}{5mm} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Macro to turn forward or backward} +%^^A % ------------------------------------------------------------ +% +%\begin{miniblock} +% \MACRO\code{\sankeyturn}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturn} The \code{\sankeyturn} macro moves the +% sankey node by turning to one side or the other and fills/draws +% this portion of the sankey path. A \emph{positive} \VAR{angle} +% turns left while a \emph{negative} \VAR{angle} turns right. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] +% \sankeynodestart{name=a,quantity=10} +% \sankeyturn{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeynodestart{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyturn[minimum radius=1cm]{b}{-45} +% \sankeynodestart{name=c,quantity=10,angle=-90,at={5,1},anchor=right} +% \sankeyturn{c}{180} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturn*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturn*} The \code{\sankeyturn*} macro moves the +% sankey node backward by turning right or left and fills/draws this +% portion of the sankey path. A \emph{positive} \VAR{angle} turns left +% while a \emph{negative} \VAR{angle} turns right. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[end style=simple,fill/.style={fill=orange!20}] +% \sankeynodeend{name=a,quantity=10} +% \sankeyturn*{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeynodeend{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyturn*[minimum radius=1cm]{b}{-45} +% \sankeynodeend{name=c,quantity=10,angle=-90,at={3,1},anchor=right} +% \sankeyturn*{c}{180} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Macros to turn left (forward or backward)} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnleft}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnleft} The +% \code{\sankeyturnleft} macro moves the sankey node by turning left +% and fills/draws this portion of the sankey path. A \emph{positive} +% \VAR{angle} turns forward while a \emph{negative} \VAR{angle} turns backward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=10} +% \sankeyturnleft{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodeend{name=b,quantity=5,angle=-135,at={1,2},anchor=left} +% \sankeyturnleft[minimum radius=1cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnleft*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnleft*} The +% \code{\sankeyturnleft*} macro moves the sankey node backward +% by turning left and fills/draws this portion of the sankey path. +% A \emph{positive} \VAR{angle} turns backward while a +% \emph{negative} \VAR{angle} turns forward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodeend{name=a,quantity=10} +% \sankeyturnleft*{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodestart{name=b,quantity=5,angle=-135,at={1,2},anchor=left} +% \sankeyturnleft*[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnleftbackward}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnleftbackward} The +% \code{\sankeyturnleftbackward} macro moves the sankey node backward +% by turning left and fills/draws this portion of the sankey path. +% A \emph{positive} \VAR{angle} turns backward while a +% \emph{negative} \VAR{angle} turns forward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodeend{name=a,quantity=10} +% \sankeyturnleftbackward{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodestart{name=b,quantity=5,angle=-135,at={1,2},anchor=left} +% \sankeyturnleftbackward[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnleftbackward*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnleftbackward*} The +% \code{\sankeyturnleftbackward*} macro moves the sankey node by turning left +% and fills/draws this portion of the sankey path. A \emph{positive} +% \VAR{angle} turns forward while a \emph{negative} \VAR{angle} turns backward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=10} +% \sankeyturnleftbackward*{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodeend{name=b,quantity=5,angle=-135,at={1,2},anchor=left} +% \sankeyturnleftbackward*[minimum radius=1cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Macros to turn right (forward or backward)} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnright}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnright} The \code{\sankeyturnright} macro +% moves the sankey node by turning right and fills/draws this portion +% of the sankey path. A \emph{positive} \VAR{angle} turns forward +% while a \emph{negative} \VAR{angle} turns backward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=10} +% \sankeyturnright[fill/.style={fill=orange!20}]{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodeend{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyturnright[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnright*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnright*} The \code{\sankeyturnright*} macro +% moves the sankey node backward by turning right and fills/draws +% this portion of the sankey path. A \emph{positive} \VAR{angle} turns +% backward while a \emph{negative} \VAR{angle} turns forward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodeend{name=a,quantity=10} +% \sankeyturnright*[fill/.style={fill=orange!20}]{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodestart{name=b,quantity=5,angle=45,at={1,1},anchor=left} +% \sankeyturnright*[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnrightbackward}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnrightbackward} +% The \code{\sankeyturnrightbackward} macro +% moves the sankey node backward by turning right and fills/draws +% this portion of the sankey path. A \emph{positive} \VAR{angle} turns +% backward while a \emph{negative} \VAR{angle} turns forward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodeend{name=a,quantity=10} +% \sankeyturnrightbackward[fill/.style={fill=orange!20}]{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodestart{name=b,quantity=5,angle=45,at={1,1},anchor=left} +% \sankeyturnrightbackward[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeyturnrightbackward*}\OPTARG{\VAR{options}}\ARG{\VAR{node +% name}}\ARG{\VAR{angle}} +% +% \DescribeMacro{\sankeyturnrightbackward*} The +% \code{\sankeyturnrightbackward*} macro moves the sankey +% node forward by turning right and fills/draws this portion +% of the sankey path. A \emph{positive} \VAR{angle} turns forward +% while a \emph{negative} \VAR{angle} turns backward. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=arrow,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=10} +% \sankeyturnrightbackward*[fill/.style={fill=orange!20}]{a}{90} +% \sankeynode[debug]{as=a} +% \sankeynode[debug]{as=a-old} +% \sankeyset{fill/.style={fill=lime!20}} +% \sankeynodeend{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyturnrightbackward*[minimum radius=.75cm]{b}{-225} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% +%^^A % ------------------------------------------------------------ +% \subsection{Links between nodes} +%^^A % ------------------------------------------------------------ +% +% The macros described in this section fill/draw a lane between two +% Sankey nodes. +% +% Note: since Sankey nodes are oriented, linking \code{A} node to +% \code{B} node does not produce the same result as linking \code{B} +% node to \code{A} node! +% +% \begin{miniblock} +% \MACRO\code{\sankeyoutin}\OPTARG{\VAR{options}}\ARG{\VAR{node +% A}}\ARG{\VAR{node B}} +% +% \DescribeMacro{\sankeyoutin} The \code{\sankeyoutin} macro +% fills/draws a lane from \VAR{node A} to \VAR{node B} using a +% Bézier curve with regular steps (10 steps by default) to +% simulate constant width lane. +% +% The constant width and the minimum curvature are \emph{not} guaranteed! +% \end{miniblock} +% +% \begin{miniblock} +% \MACRO\code{\sankeydubins}\OPTARG{\VAR{options}}\ARG{\VAR{node +% A}}\ARG{\VAR{node B}} +% +% \DescribeMacro{\sankeydubins} % +% The \code{\sankeydubins} macro fills/draws a lane between +% \VAR{node A} and \VAR{node B} using a Dubins +% path\footnote{\url{https://en.wikipedia.org/wiki/Dubins_path}}. +% +% The constant width and the minimum curvature are guaranteed. +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Comparison between \texttt{outin} and \texttt{dubins} +% paths} +%^^A % ------------------------------------------------------------ +% +% The following diagrams compare \texttt{outin} path with +% 10 steps (orange), \texttt{outin} path with 2 steps (red) +% and \texttt{dubins} path (lime) in various positions. +% +% \begin{miniblock} +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=simple,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=5} +% \sankeynodeend{name=b,at={4,3},quantity=5} +% \sankeyoutin{a}{b} +% +% \sankeyset{fill/.style={fill=red!20}} +% \sankeynodestart{name=a,at={2,0},quantity=5} +% \sankeynodeend{name=b,at={6,3},quantity=5} +% \sankeyoutin[outin steps=2]{a}{b} +% +% \sankeyset{fill/.style={fill=lime!40}} +% \sankeynodestart{name=a,at={4,0},quantity=5} +% \sankeynodeend{name=b,at={(8,3},quantity=5} +% \sankeydubins[minimum radius=5mm]{a}{b} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=simple,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=5} +% \sankeynodeend{name=b,at={2,3},quantity=5} +% \sankeyoutin{a}{b} +% +% \sankeyset{fill/.style={fill=red!20}} +% \sankeynodestart{name=a,at={2,0},quantity=5} +% \sankeynodeend{name=b,at={4,3},quantity=5} +% \sankeyoutin[outin steps=2]{a}{b} +% +% \sankeyset{fill/.style={fill=lime!40}} +% \sankeynodestart{name=a,at={4,0},quantity=5} +% \sankeynodeend{name=b,at={(6,3},quantity=5} +% \sankeydubins[minimum radius=5mm]{a}{b} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% \begin{miniblock} +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=simple,end style=arrow] +% \sankeyset{fill/.style={fill=orange!20}} +% \sankeynodestart{name=a,quantity=5} +% \sankeynodeend{name=b,at={0,3},quantity=5} +% \sankeyoutin{a}{b} +% +% \sankeyset{fill/.style={fill=red!20}} +% \sankeynodestart{name=a,at={2,0},quantity=5} +% \sankeynodeend{name=b,at={2,3},quantity=5} +% \sankeyoutin[outin steps=2]{a}{b} +% +% \sankeyset{fill/.style={fill=lime!40}} +% \sankeynodestart{name=a,at={4,0},quantity=5} +% \sankeynodeend{name=b,at={(4,3},quantity=5} +% \sankeydubins[minimum radius=5mm]{a}{b} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Examples of \texttt{dubins} paths} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram}[start style=simple,end style=arrow] +% \sankeyset{ +% fill/.style={fill=lime!40}, +% draw/.style={draw=green!50!black,line width=2pt}, +% } +% +% \sankeynodestart{name=a,quantity=5} +% \sankeynodeend{name=b,at={0,2},quantity=5} +% \sankeydubins[minimum radius=2mm]{a}{b} +% +% \fill[green!50!black] (2,0) coordinate (c) circle(2pt); +% \sankeynodestart{name=a,at={[shift={(c)}]90:5mm},quantity=5} +% \sankeynodeend{name=b,at={[shift={(c)}]150:5mm},angle=60,quantity=5} +% \sankeydubins[minimum radius=2.5mm]{a}{b} +% +% \sankeynodestart{name=a,at={3.5,0},quantity=5} +% \sankeynodeend{name=b,at={3.5,.75},angle=-180,quantity=5} +% \sankeydubins[minimum radius=5mm]{a}{b} +% +% \sankeynodestart{name=a,at={7,1},quantity=5} +% \sankeynodeend{name=b,at={7,1.75},quantity=5} +% \sankeydubins[minimum radius=2.5mm]{a}{b} +% +% \sankeynodestart{name=a,at={9,0},quantity=5} +% \sankeynodeend{name=b,at={9,2},angle=180,quantity=5} +% \sankeydubins[minimum radius=2.5mm]{a}{b} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsection{Pure filling/drawing macros} +%^^A % ------------------------------------------------------------ +% +% \begin{miniblock} +% \MACRO\code{\sankeystart}\OPTARG{\VAR{options}}\ARG{\VAR{name}} +% +% \DescribeMacro{\sankeystart} % +% The \code{\sankeystart} fills/draws a starting extremity attached to +% the preexisting Sankey node \VAR{name}: +% +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram} +% [start style=arrow,fill/.style={fill=cyan!20},draw/.style={draw=blue}] +% \sankeynode{name=a,quantity=10} +% \sankeystart{a} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeystart{b} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right} +% \sankeystart{c} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +%^^A % ------------------------------------------------------------ +% +% +% \begin{miniblock} +% \MACRO\code{\sankeyend}\OPTARG{\VAR{options}}\ARG{\VAR{name}} +% +% \DescribeMacro{\sankeyend} % +% The \code{\sankeyend} fills/draws an ending extremity attached to +% the preexisting Sankey node \VAR{name}: +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram} +% [end style=simple,fill/.style={fill=cyan!20},draw/.style={draw=blue}] +% \sankeynode{name=a,quantity=10} +% \sankeyend{a} +% \sankeynode{name=b,quantity=5,angle=45,at={2,1},anchor=left} +% \sankeyend{b} +% \sankeynode{name=c,quantity=20,angle=-90,at={5,1},anchor=right} +% \sankeyend{c} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% % +% {\centering\input{\samplecodename}\par} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \subsection{Forked node} +%^^A % ------------------------------------------------------------ +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Create and fork a Sankey node} +%^^A % ------------------------------------------------------------ +% +% \changes{v3.0}{2021/03/14}{add keys to fork a Sankey node during its +% creation} +% +% \begin{miniblock} +% When creating a new Sankey node, the \code{forked} and % +% \code{fork anchor} keys allow to fork the node directly \emph{and} to +% anchor it on an anchor of a forked subnode. +% +% \begin{sankeyoption}[/sankey/node parameters]{forked}{\{\VAR{quantity/name pairs}\}}{}{} +% The \VAR{quantity/name pairs} is a comma separated list of +% \emph{quantity/name} pairs (one for each subnode, from left to +% right). The sum of all quantities \emph{must} be equal to the quantity +% of the new node to fork. +% \end{sankeyoption} +% +% \begin{sankeyoption}[/sankey/node parameters]{fork anchor}{\VAR{node.anchor}}{}{} +% An anchor belonging to the new node \emph{or} belonging to a subnode +% (the anchor name must be prefixed by the name of the +% node). \emph{Note:} when a \code{fork anchor} key is supplied, the +% \code{anchor} key is ignored (with a \emph{warning} message). +% \end{sankeyoption} +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram} +% \sankeyset{ +% start style=arrow,end style=arrow, +% fill/.style={fill=yellow!10,line width=0pt,draw=yellow!10} +% } +% +% \sankeynode[debug]{ +% name=a,quantity=40,angle=-80, +% forked={25/b,10/c,5/d}, +% fork anchor=c.right, +% } +% +% \sankeyadvance*{b}{1cm} +% \sankeyturn*[minimum radius=2cm]{c}{-30} +% \sankeyturn*[minimum radius=2cm]{c}{30} +% \sankeyturn*[minimum radius=5mm]{d}{-90} +% \sankeyadvance{a}{1.5cm} +% \foreach \nodename in {b,c,d}{ \sankeystart{\nodename} } +% \sankeyend{a} +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Fork a Sankey node} +%^^A % ------------------------------------------------------------ +% \begin{miniblock} +% \MACRO\code{\sankeyfork}\OPTARG{\VAR{options}}\ARG{\VAR{name}}\ARG{\VAR{quantity/name pairs}} +% +% \DescribeMacro{\sankeyfork} % +% The \code{\sankeyfork} macro splits the preexisting Sankey node +% named \VAR{name} in a list of new Sankey subnodes. The +% \VAR{quantity/name pairs} is a comma separated list of +% \emph{quantity/name} pairs, one for each subnode from left to +% right. The sum of all quantities \emph{must} be equal to the +% quantity of the node to fork. +% +% \begin{VerbatimOut}[gobble=2]{\samplecodename} +% \begin{tikzpicture} +% \begin{sankeydiagram} +% \sankeynode{name=a,quantity=40,angle=-45} +% \sankeyfork[debug]{a}{25/b,10/c,5/d} +% \path (a.left) rectangle (a.right); %^^A create a bounding box +% \end{sankeydiagram} +% \end{tikzpicture} +% \end{VerbatimOut} +% % +% {\centering\input{\samplecodename}\par} +% % +% \lstinputlisting[style=LaTeXsmall]{\samplecodename} +% \end{miniblock} +% +%^^A % ------------------------------------------------------------ +% \section{Miscellaneous} +%^^A % ------------------------------------------------------------ +% +%^^A % ------------------------------------------------------------ +% \subsection{The \texttt{debug} layer} +%^^A % ------------------------------------------------------------ +% +% The options \code{debug} key uses the \code{sankeydebug} layer to draw +% above the \code{main} TikZ layer (via \code{\pgfsetlayers}, the +% \code{sankey} package installs four layers: \code{background}, +% \code{main}, \code{foreground}, \code{sankeydebug}). +% +% The four following styles define how to display debug information: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \sankeyset{ +% debug color/.style={/utils/exec={\colorlet{debug color}{#1}}}, +% % 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}, +% }, +% } +% \end{lstlisting} +% +%^^A % ------------------------------------------------------------ +% \subsection{The \texttt{dubins} TikZ library} +% \label{sec:dubins} +%^^A % ------------------------------------------------------------ +% +% The \code{sankey} package uses the \code{dubins} TikZ library (the +% \code{tikzlibrarydubins.code.tex} file) to compute Dubins paths. The +% documentation for this library does not yet exist. +% +%^^A % ------------------------------------------------------------ +% \subsection{How to duplicate a Sankey node} +%^^A % ------------------------------------------------------------ +% +% \MACRO\code{\sankeynodealias}\ARG{\VAR{origname}}\ARG{\VAR{clonename}} +% +% \DescribeMacro{\sankeynodealias} % +% The \code{\sankeynodealias} macro clones the Sankey node named +% \VAR{origname} into the Sankey node named \VAR{clonename}. +% +% So, you can clone a Sankey node via two methods: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \sankeynode{name=a,quantity=10} +% \sankeynode{as=a,name=b} +% \end{lstlisting} +% +% \begin{lstlisting}[style=LaTeXsmall] +% \sankeynode{name=a,quantity=10} +% \sankeynodealias{a}{b} +% \end{lstlisting} +% +%^^A % ------------------------------------------------------------ +% \subsection{How to define new start and end styles} +%^^A % ------------------------------------------------------------ +% +% Here are the definitions of the \code{arrow} styles: +% +% \begin{lstlisting}[style=LaTeXsmall] +% \sankeyset{ +% %% 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) +% }, +% } +% \end{lstlisting} +% +%^^A % ------------------------------------------------------------ +% \section{Todo} +%^^A % ------------------------------------------------------------ +% +% \begin{itemize} +% \item Document the \code{dubins} TikZ library. +% \item Add a tutorial. +% \item Add examples with cycle(s). +% \end{itemize} +% +% ^^A % ------------------------------------------------------------ +% \clearpage +% +% \manualparts +% +% \part{Examples} +% \label{examples} +%^^A % ------------------------------------------------------------ +% { +% \setlength{\parskip}{0pt} +% \localtableofcontents +% \listoffigures +% } +% +% \tikzset{every picture/.style={}} +%^^A % ------------------------------------------------------------ +% +%^^A % ------------------------------------------------------------ +% \clearpage +% \section{Simple example} +%^^A % ------------------------------------------------------------ +% +% \embedfile[mimetype=text/plain]{sankey-example1.tex} +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example1.tex}} +% \caption{Simple example} +% \label{fig:simple-example} +% \end{figure} +% +% See figure~\vref{fig:simple-example}. The \code{sankey-example1.tex} +% file contains the following code and is an attachement of the current +% PDF document. +% +% \lstinputlisting[style=LaTeXsmall]{sankey-example1.tex} +% +% \iffalse +%<*example1> +\begin{tikzpicture} + \begin{sankeydiagram}%[debug] + \colorlet{cold}[rgb]{cyan!75!blue!50!white} + \colorlet{hot}[rgb]{red!50!orange!75!white} + \sankeyset{ + ratio=90pt/6,minimum radius=15pt, + start style=simple,end style=simple, + draw/.style={ + draw=blue!50!cyan, + line width=1pt,line cap=round,line join=round, + }, + cold/.style={ + fill/.style={ + draw=cold,line width=0pt,fill=cold, + }, + }, + cold to hot/.style={ + fill/.style={ + fill=none,top color=cold, + bottom color=hot,middle color=yellow, + }, + }, + hot/.style={ + fill/.style={ + draw=hot,line width=0pt,fill=hot, + }, + }, + } + + \sankeyset{cold} + \sankeynodestart{name=p0,at={100,0},angle=-90,quantity=6} + \sankeyadvance{p0}{50pt} + \sankeyfork{p0}{3/p1,3/p2} + \sankeyturnleft{p1}{90} + \sankeyadvance{p1}{20pt} + \sankeyadvance{p2}{60pt} + \sankeyfork{p2}{2/p3,1/p4} + \sankeyturnleft{p3}{90} + \sankeyadvance{p3}{50pt} + \sankeyfork{p3}{1/p5,1/p6} + \sankeyadvance{p5}{70pt} + \sankeyfork{p1}{1/p7,1/p8,1/p9} + \sankeyadvance{p7}{50pt} + \sankeyadvance{p9}{50pt} + \sankeyadvance{p4}{40pt} + \sankeyturnleft{p4}{90} + \sankeyadvance{p4}{65pt} + \sankeyadvance{p7}{40pt} + \sankeynode{ + name=p11,at={[shift={(50pt,-15pt)}]p7},quantity=3, + forked={1/p7a,1/p9a,1/p5a}, + } + \sankeyoutin{p7}{p7a} + \sankeyoutin{p9}{p9a} + \sankeyoutin{p5}{p5a} + \sankeyadvance{p11}{30pt} + \sankeyend{p11} + \sankeyturnright{p8}{90} + \sankeyturnright{p6}{90} + \sankeyturnright{p4}{90} + \sankeyset{hot} + \sankeyadvance[cold to hot]{p8}{40pt} + \sankeynode{ + name=p10,at={[shift={(-15pt,-60pt)}]p8},angle=-90,quantity=3, + forked={1/p8a,1/p6a,1/p4a}, + } + \sankeyoutin[cold to hot]{p4}{p4a} + \sankeyoutin[cold to hot]{p6}{p6a} + \sankeyoutin{p8}{p8a} + \sankeyadvance{p10}{30pt} + \sankeyend{p10} + \end{sankeydiagram} +\end{tikzpicture} +%</example1> +% \fi +% +%^^A % ------------------------------------------------------------ +% \clearpage +% \section{Energy diagram} +%^^A % ------------------------------------------------------------ +% +% \embedfile[mimetype=text/plain]{sankey-example-energy.tex} +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example-energy.tex}} +% \caption{Energy diagram} +% \label{fig:very-simple-example} +% \end{figure} +% +% This example comes from +% \href{https://ibphysicsblog.wordpress.com/2015/10/23/sankey-diagrams/}{IB +% Pysics Blog} by Kyu Won Shim. +% +% See figure~\vref{fig:very-simple-example}. The \code{sankey-example-energy.tex} +% file contains the following code and is an attachement of the current +% PDF document. +% +% \lstinputlisting[style=LaTeXsmall]{sankey-example-energy.tex} +% +% \iffalse +%<*example-energy> +\begin{tikzpicture} + % font choice + \renewcommand\rmdefault{txr}\rmfamily\footnotesize + \sisetup{ + round-mode=places, + round-precision=1, + add-decimal-zero, + round-integer-to-decimal, + } + \begin{sankeydiagram} + \colorlet{energy}{blue!30!cyan!80!black} + \colorlet{lost energy}{red!50!orange!90!black} + \sankeyset{ + ratio=13em/100, + minimum radius=1em, + start style=simple,end style=simple, + draw/.style={draw=none,line width=0}, + energy/.style={ + fill/.style={ + draw=energy, + line width=0, + fill=energy, + } + }, + lost energy/.style={ + fill/.style={ + draw=lost energy, + line width=0, + fill=lost energy, + } + } + } + + \newcommand\abovelabel[2]{ % valname, label + \node[anchor=south east,align=center,inner xsep=0] at (#1.left) {#2}; + } + + \newcommand\energylabel[1]{ % valname + \node[anchor=north east,text=energy,inner xsep=0] at (#1.right) + {\num{\sankeygetnodeqty{#1}}}; + } + + \newcommand\lostenergylabel[2]{ % valname, label + \node[anchor=north,text=lost energy] at ([yshift=-2.5mm]#1.center) + (value) + {\num{\sankeygetnodeqty{#1}}}; + \node[anchor=north,inner sep=0,align=center] at (value.south) {#2}; + } + + \newcommand\lostenergylabelbottom[2]{ % valname, label + \draw[draw=lost energy,dashed,thick] + ([yshift=-3mm]#1.center) coordinate (#1) -- ([yshift=-3mm]#1.center); + \lostenergylabel{#1}{#2} + } + + \sankeynode{name=Co,quantity=100.0} + \path (Co.right) ++(0,-7mm) coordinate (c); + + \newcommand\turnandstop[2]{ % valname, label + \begingroup + \sankeyset{lost energy} + \sankeyturnright{#1}{90} + \sankeynode{as=#1,name=#1-stop,at={#1 |- c}} + \sankeyoutin{#1}{#1-stop} + \sankeynode{as=#1-stop,name=#1} + \sankeyend{#1} + \lostenergylabel{#1}{#2} + \endgroup + } + + \newcommand\turnandstopbottom[2]{ % valname, label + \begingroup + \sankeyset{lost energy} + \sankeyturnright{#1}{90} + \sankeynode{as=#1,name=#1-stop,at={#1 |- c}} + \sankeyoutin{#1}{#1-stop} + \sankeynode{as=#1-stop,name=#1} + \sankeyend{#1} + \lostenergylabelbottom{#1}{#2} + \endgroup + } + + \def\hshift{6.25em} + + \sankeyadvance[energy]{Co}{1.2*\hshift} + \abovelabel{Co}{\textbf{Coal}\\(Primary energy)} + \energylabel{Co} + \sankeyfork{Co}{35/El1,65/Pg} + \turnandstop{Pg}{Power generation} + + \sankeyadvance[energy]{El1}{1.8*\hshift} + \abovelabel{El1}{\textbf{Electricity}\\(Secondary energy)} + \energylabel{El1} + \sankeyfork{El1}{33.5/El2,1.5/Tr} + \turnandstopbottom{Tr}{Transmission} + + \sankeyadvance[energy]{El2}{.65*\hshift} + \energylabel{El2} + \sankeyfork{El2}{31.5/El3,2.0/Di} + \turnandstop{Di}{Distribution} + + \sankeyadvance[energy]{El3}{.65*\hshift} + \energylabel{El3} + \sankeyfork{El3}{31.0/El4,0.5/Wi} + \turnandstopbottom{Wi}{Wiring} + + \sankeyadvance[energy]{El4}{.65*\hshift} + \abovelabel{El4}{\textbf{Electricity}\\(Final energy)} + \energylabel{El4} + \sankeyfork{El4}{3.0/Lr1,28.0/Lb} + \turnandstop{Lb}{Lightbulb} + + \sankeyadvance[energy]{Lr1}{1.1*\hshift} + \abovelabel{Lr1}{\textbf{Light radiation}\\(Useful energy)} + \energylabel{Lr1} + \sankeyfork{Lr1}{2.0/Lr2,1.0/Ls} + \turnandstopbottom{Ls}{Lampshade} + + \sankeyadvance[energy]{Lr2}{.6*\hshift} + \energylabel{Lr2} + \sankeyfork{Lr2}{1.0/Il,1.0/Id} + \turnandstop{Id}{Idle} + + \sankeyadvance[energy]{Il}{.6*\hshift} + \abovelabel{Il}{\textbf{Illumination}\\(Energy services)} + \energylabel{Il} + \sankeyend[energy]{Il} + \end{sankeydiagram} +\end{tikzpicture} +%</example-energy> +% \fi +%^^A % ------------------------------------------------------------ +% \clearpage +% \section{Example from question on TeX.se} +%^^A % ------------------------------------------------------------ +% +% \changes{v3.0}{2021/03/14}{fix bad names in second example} +% +% \embedfile[mimetype=text/plain]{sankey-example2.tex} +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example2}} +% \caption{Example from TeX.se question} +% \label{fig:texse-example} +% \end{figure} +% +% This example came from +% \href{https://tex.stackexchange.com/q/40159/14500}{this question} on +% \href{https://tex.stackexchange.com/}{TeX.StackExchange}. +% +% See figure~\vref{fig:texse-example}. The \code{sankey-example2.tex} +% file contains the following code and is an attachement of the current +% PDF document. +% +% \lstinputlisting[style=LaTeXsmall]{sankey-example2} +% +% \iffalse +%<*example2> +\begin{tikzpicture} + \renewcommand*\sfdefault{txss} + + \begin{sankeydiagram}%[debug] + \sankeyset{ + ratio=4cm/524.3, + minimum radius=3mm, + start style=arrow, + end style=arrow, + fill/.style={ + line width=0pt, + fill=cyan!50!blue!50!black, + draw=cyan!50!blue!50!black, + }, + draw/.style={draw=none}, + every node/.style={angle=-90}, + } + + \sankeynodestart{name=B,at={-.5,0},quantity=7.2} + \coordinate[below=1mm of B.center] (B label); + \sankeyadvance{B}{5mm} + \sankeynodestart{name=GI,at={1,0},quantity=137.3} + \coordinate[below=1mm of GI.center] (GI label); + \sankeyadvance{GI}{5mm} + \sankeynodestart{name=I,at={4,0},quantity=397.8} + \coordinate[below=1mm of I.center] (I label); + \sankeynode{ + name=EI,at={2.86,-3},quantity=542.3, + forked={397.8/Ia,137.3/GIa,7.2/Ba} + } + \sankeydubins[minimum radius=1.2cm]{I}{Ia} + \sankeyoutin{GI}{GIa} + \sankeyoutin{B}{Ba} + \sankeyadvance{EI}{5mm} + \coordinate (EI label) at (EI); + \sankeyadvance{EI}{5mm} + \sankeyfork{EI}{63.1/EB,479.2/P} + + \sankeyturnleft{EB}{90} + \sankeyadvance{EB}{4cm} + \coordinate (EB label) at ($(EB)!.5!(EB-old)$); + \sankeyend{EB} + + \sankeyadvance{P}{10mm} + \coordinate (P label) at (P); + \sankeyadvance{P}{5mm} + + \sankeyfork{P}{33.5/NV,445.7/P-NV} + + { + \colorlet{NV color}{cyan!80!lime!50!gray} + \sankeyset{fill/.append style={fill=NV color,draw=NV color}} + \sankeyturnleft{NV}{90} + \sankeynode{as=NV,name=NV2,at=NV -| EB} + \sankeyoutin{NV}{NV2} + \coordinate (NV label) at (NV -| EB label); + \sankeyend{NV2} + } + + \sankeyadvance{P-NV}{10mm} + \sankeyfork{P-NV}{118.1/U,327.6/P-NV-U} + + { + \sankeyset{ + fill/.style={fill=orange!70!gray!50,draw=orange!70!gray!50} + } + \sankeyturnleft{U}{90} + \sankeynode{as=U,name=U2,at=U -| EB} + \sankeyoutin{U}{U2} + \coordinate (U label) at (U -| EB label); + \sankeyend{U2} + } + + \sankeyadvance{P-NV-U}{10mm} + \sankeyfork{P-NV-U}{327.2/P-NV-U-SD,0.4/SD} + + { + \sankeyturnright{SD}{90} + \sankeyadvance{SD}{15mm} + \coordinate (SD label) at (SD); + \sankeyadvance{SD}{15mm} + \sankeyend{SD} + } + + \sankeyadvance{P-NV-U-SD}{8mm} + \sankeyfork{P-NV-U-SD}{18.8/VE,308.4/E} + + { + \sankeyset{fill/.append style={orange!70!gray!30}} + \sankeyturnleft{VE}{90} + \sankeynode{as=VE,name=VE2,at=VE -| EB} + \sankeyoutin{VE}{VE2} + \coordinate (VE label) at (VE -| EB label); + \sankeyend{VE2} + } + + \sankeyadvance{E}{8mm} + \coordinate (E label) at (E); + \sankeyadvance{E}{20mm} + \sankeyfork{E}{135.1/H+GHD,87.2/V,86.1/In} + + \sankeyturnright{In}{90} + \sankeyadvance{In}{10mm} + \sankeyturnleft{In}{90} + \sankeyadvance{In}{5mm} + \coordinate (In label) at (In); + \sankeyadvance{In}{10mm} + \sankeyend{In} + + \sankeynode{as=V,name=V2,at=V|-In label} + \sankeyoutin{V}{V2} + \coordinate (V label) at (V2); + \sankeyadvance{V2}{10mm} + \sankeyend{V2} + + \sankeyturnleft{H+GHD}{90} + \sankeyadvance{H+GHD}{5mm} + \sankeyfork{H+GHD}{47.0/GHD,88.1/H} + + \sankeyturnright{H}{90} + \sankeynode{as=H,name=H2,at=H|-In label} + \sankeyoutin{H}{H2} + \coordinate (H label) at (H2); + \sankeyadvance{H2}{10mm} + \sankeyend{H2} + + \sankeyadvance{GHD}{30mm} + \sankeyturnright{GHD}{90} + \sankeynode{as=GHD,name=GHD2,at=GHD|-In label} + \sankeyoutin{GHD}{GHD2} + \coordinate (GHD label) at (GHD2); + \sankeyadvance{GHD2}{10mm} + \sankeyend{GHD2} + \end{sankeydiagram} + + % labels + \tikzset{ + label/.style={ + fill=white,fill opacity=.8,text opacity=1, + inner sep=1mm, + text=cyan!50!blue!50!black, + inner xsep=2mm, + font=\sffamily\bfseries\footnotesize, + align=center, + }, + } + \node[label,anchor=north] (B label) at (B label) {7.2}; + \node[label,left=1mm of B label] {Bestands-\\entnahme}; + \node[label,anchor=north] at (GI label) {137.3}; + \node[label,above=5mm of GI label] {Gewinnung\\im Inland}; + \node[label,anchor=north] at (I label) {397.8}; + \node[label,above=5mm of I label] {Import}; + + \node[label] at (EI label) {542.3\\Energieaufkommen im Inland}; + + \node[label,anchor=center] (EB label) at (EB label) {63.1}; + \node[label,above=1mm of EB label] {Export und\\Bunkerung}; + + \node[label] at (P label) {479.2\\Primärenergieverbrauch}; + + \node[label,anchor=center] (NV label) at (NV label) {33.5}; + \node[label,above=0mm of NV label] {Nichtenergetischer Verbrauch}; + + \node[label,anchor=center] (U label) at (U label) {118.1}; + \node[label,below=3mm of U label] {Umwandlungsverluste}; + + \node[label,anchor=center] (SD label) at (SD label) {0.4}; + \node[label,above=0mm of SD label] {Statistische\\Differenzen}; + + \node[label,anchor=center] (VE label) at (VE label) {18.8}; + \node[label,below=0mm of VE label] {Verbrauch in den\\Energiesktoren}; + + \node[label,anchor=north] (E label) at (E label) + {308.4\\Endenergieverbrauch}; + + \node[label,anchor=north] (In label) at (In label) {86.1}; + \node[label,anchor=north,below=1cm of In label] {Industrie}; + + \node[label,anchor=north] (V label) at (V label) {87.2}; + \node[label,anchor=north,below=1cm of V label] {Verkehr}; + + \node[label,anchor=north] (H label) at (H label) {88.1}; + \node[label,anchor=north,below=1cm of H label] {Haushalte}; + + \node[label,anchor=north] (GHD label) at (GHD label) {47.0}; + \node[label,anchor=north,below=1cm of GHD label] + {Gewerbe, Handel\\Diensleistungen}; +\end{tikzpicture} +%</example2> +% \fi +% +%^^A % ------------------------------------------------------------ +% \clearpage +% \section{Reproduction of an example from Google Charts documentation} +%^^A % ------------------------------------------------------------ +% +% \changes{v3.0}{2021/03/14}{add the reproduction of an example from +% Google Charts documentation} +% +% \embedfile[mimetype=text/plain]{sankey-example3.tex} +% +% This example is a reproduction of an example of Google +% Charts Documentation\footnote{\url{https://developers.google.com/chart/interactive/docs/gallery/sankey}}. +% +% See figure \vref{fig:google-example}. The \code{sankey-example3.tex} +% file contains the following code and is an attachement of the current +% PDF document. +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example3}} +% \caption{Reproduction of an example from Google Charts +% documentation} +% \label{fig:google-example} +% \end{figure} +% +% \lstinputlisting[style=LaTeXsmall]{sankey-example3} +% +% \iffalse +%<*example3> +\begin{tikzpicture} + \begin{sankeydiagram}%[debug] + \sffamily + \sankeyset{ + ratio=1cm/10, + outin steps=2, + draw/.style={draw=none,line width=0pt}, + color/.style={fill/.style={fill=#1,fill opacity=.75}}, + shade/.style 2 args={fill/.style={left color=#1, + right color=#2,fill opacity=.5}}, + % colors + @define HTML color/.code args={#1/#2}{\definecolor{#1}{HTML}{#2}}, + @define HTML color/.list={ + cyan/a6cee3,lime/b2df8a,red/fb9a99,orange/fdbf6f, + violet/cab2d6,yellow/ffff99,blue/1f78b4,green/33a02c + }, + % colors of countries + @let country color/.code args={#1/#2}{\colorlet{#1}[rgb]{#2}}, + @let country color/.list={ + CA/red,US/orange,MX/orange,BR/cyan,FR/lime,GB/red, + SP/lime,PT/cyan,ML/blue,SN/violet,MA/yellow, + AO/violet,ZA/yellow,IN/green,JP/green,CN/blue + }, + } + \def\vdist{5mm} + \def\hwidth{.5em} + \def\hdist{4.1cm} + + \sankeynode{name=CA,quantity=7} + \sankeynode{name=US,quantity=8,at={[yshift=\vdist]CA.left},anchor=right} + \sankeynode{name=MX,quantity=8,at={[yshift=\vdist]US.left},anchor=right} + \sankeynode{name=BR,quantity=8,at={[yshift=\vdist]MX.left},anchor=right} + + \foreach \country in {CA,US,MX,BR}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{CA}{1/CA-to-PT,1/CA-to-GB,5/CA-to-FR} + \sankeyfork{US}{1/US-to-PT,1/US-to-SP,5/US-to-GB,1/US-to-FR} + \sankeyfork{MX}{1/MX-to-PT,5/MX-to-SP,1/MX-to-GB,1/MX-to-FR} + \sankeyfork{BR}{5/BR-to-PT,1/BR-to-SP,1/BR-to-GB,1/BR-to-FR} + + \sankeynode{name=FR,quantity=11, + at={[xshift=\hdist]CA.right},anchor=right} + \sankeynode{name=GB,quantity=11, + at={[yshift=\vdist]FR.left},anchor=right} + \sankeynode{name=SP,quantity=7, + at={[yshift=\vdist]GB.left},anchor=right} + \sankeynode{name=PT,quantity=8, + at={[yshift=\vdist]SP.left},anchor=right} + + \sankeyfork{FR} + {1/FR-from-BR,1/FR-from-MX,1/FR-from-US,5/FR-from-CA,3/FR-from-00} + \sankeyfork{GB} + {1/GB-from-BR,1/GB-from-MX,5/GB-from-US,1/GB-from-CA,3/GB-from-00} + \sankeyfork{SP}{1/SP-from-BR,5/SP-from-MX,1/SP-from-US} + \sankeyfork{PT}{5/PT-from-BR,1/PT-from-MX,1/PT-from-US,1/PT-from-CA} + + \foreach \country in {FR,GB,SP,PT}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{FR}{1/FR-to-ZA,1/FR-to-AO,3/FR-to-MA,3/FR-to-SN,3/FR-to-ML} + \sankeyfork{GB}{7/GB-to-ZA,1/GB-to-AO,2/GB-to-MA,1/GB-to-SN} + \sankeyfork{SP}{1/SP-to-ZA,3/SP-to-MA,1/SP-to-SN,2/SP-to-00} + \sankeyfork{PT}{3/PT-to-ZA,2/PT-to-AO,1/PT-to-MA,1/PT-to-SN,1/PT-to-00} + + \sankeynode{name=ML,quantity=9, + at={[xshift=\hdist]FR.right},anchor=right} + \sankeynode{name=SN,quantity=9, + at={[yshift=\vdist]ML.left},anchor=right} + \sankeynode{name=MA,quantity=9, + at={[yshift=\vdist]SN.left},anchor=right} + \sankeynode{name=AO,quantity=9, + at={[yshift=\vdist]MA.left},anchor=right} + \sankeynode{name=ZA,quantity=12, + at={[yshift=\vdist]AO.left},anchor=right} + + \sankeyfork{ML}{3/ML-from-FR,6/Mail-from-00} + \sankeyfork{SN} + {1/SN-from-PT,1/SN-from-SP,1/SN-from-GB,3/SN-from-FR,3/SN-from-00} + \sankeyfork{MA}{1/MA-from-PT,3/MA-from-SP,2/MA-from-GB,3/MA-from-FR} + \sankeyfork{AO}{2/AO-from-PT,1/AO-from-GB,1/AO-from-FR,5/AO-from-00} + \sankeyfork{ZA}{3/ZA-from-PT,1/ZA-from-SP,7/ZA-from-GB,1/ZA-from-FR} + + \foreach \country in {ML,SN,MA,AO,ZA}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{ML}{5/ML-to-CN,3/ML-to-JP,1/ML-to-IN} + \sankeyfork{SN}{5/SN-to-CN,3/SN-to-JP,1/SN-to-IN} + \sankeyfork{MA}{5/MA-to-CN,3/MA-to-JP,1/MA-to-IN} + \sankeyfork{AO}{5/AO-to-CN,3/AO-to-JP,1/AO-to-IN} + \sankeyfork{ZA}{5/ZA-to-CN,3/ZA-to-JP,1/ZA-to-IN,3/ZA-to-00} + + \sankeynode{name=IN,quantity=5, + at={[xshift=\hdist]ML.right},anchor=right} + \sankeynode{name=JP,quantity=15, + at={[yshift=\vdist]IN.left},anchor=right} + \sankeynode{name=CN,quantity=25, + at={[yshift=\vdist]JP.left},anchor=right} + + \sankeyfork{IN} + {1/IN-from-ZA,1/IN-from-AO,1/IN-from-MA,1/IN-from-SN,1/IN-from-ML} + \sankeyfork{JP} + {3/JP-from-ZA,3/JP-from-AO,3/JP-from-MA,3/JP-from-SN,3/JP-from-ML} + \sankeyfork{CN} + {5/CN-from-ZA,5/CN-from-AO,5/CN-from-MA,5/CN-from-SN,5/CN-from-ML} + + \foreach \country in {IN,JP,CN}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \foreach \startcountry/\countries in { + CA/{PT,GB,FR}, US/{PT,SP,GB,FR}, MX/{PT,SP,GB,FR}, + BR/{PT,SP,GB,FR}, FR/{ML,SN,MA,AO,ZA}, GB/{SN,MA,AO,ZA}, + SP/{SN,MA,ZA}, PT/{SN,MA,AO,ZA}, ML/{IN,JP,CN}, + SN/{IN,JP,CN}, MA/{IN,JP,CN}, AO/{IN,JP,CN}, + ZA/{IN,JP,CN}} + { + \foreach \endcountry in \countries { + \sankeyoutin[shade={\startcountry}{\endcountry}] + {\startcountry-to-\endcountry}{\endcountry-from-\startcountry} + } + } + + \foreach \country/\countryname in {CA/Canada, US/USA, MX/Mexico, + BR/Brazil, FR/France, GB/England, SP/Spain, PT/Portugal} + { + \node[anchor=west,inner sep=.1em,font=\small] + at (\country) {\countryname\vphantom{Ag}}; + } + + \foreach \country/\countryname in { + ML/Mali, SN/Senegal, MA/Morocco, AO/Angola, + ZA/South Africa, IN/India, JP/Japan, CN/China} + { + \node[anchor=east,inner sep=.1em,font=\small] + at (\country-old) {\countryname\vphantom{Ag}}; + } + \end{sankeydiagram} +\end{tikzpicture} +%</example3> +% \fi +% +%^^A % ------------------------------------------------------------ +% \subsection{Variation} +%^^A % ------------------------------------------------------------ +% +% Here is a variation of the previous example using the \code{rotate} +% key. +% +% See figure \vref{fig:google-example-variation}. The +% \code{sankey-example3-variation.tex} file contains the following code +% and is an attachement of the current PDF document. +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example3-variation}} +% \caption{Reproduction of an example from Google Charts documentation +% -- variation using the \protect\texttt{rotate} key.} +% \label{fig:google-example-variation} +% \end{figure} +% +% \lstinputlisting[style=LaTeXsmall]{sankey-example3-variation} +% +% \iffalse +%<*example3-variation> +\begin{tikzpicture}[rotate=-90] + \begin{sankeydiagram}[rotate=-90] + \sffamily + \sankeyset{ + ratio=1.7cm/10, + outin steps=2, + start style=arrow, + end style=simple, + draw/.style={draw=white,line width=.4pt}, + color/.style={fill/.style={fill=#1,fill opacity=.75}}, + shade/.style 2 args={fill/.style={ + fill=none,line width=0, + top color=#1,bottom color=#2, + middle color=#1!50!#2!50!white, + fill opacity=.75}}, + % colors + @define HTML color/.code args={#1/#2}{\definecolor{#1}{HTML}{#2}}, + @define HTML color/.list={ + cyan/a6cee3,lime/b2df8a,red/fb9a99,orange/fdbf6f, + violet/cab2d6,yellow/ffff99,blue/1f78b4,green/33a02c + }, + % colors of countries + @let country color/.code args={#1/#2}{\colorlet{#1}[rgb]{#2}}, + @let country color/.list={ + CA/red,US/orange,MX/lime,BR/violet,FR/yellow,GB/blue, + SP/green,PT/cyan,ML/cyan,SN/red,MA/orange, + AO/violet,ZA/lime,IN/blue,JP/yellow,CN/green + }, + } + \def\vdist{5mm} + \def\hwidth{1em} + \def\hdist{6cm} + + \sankeynode{name=CA,quantity=7} + \sankeynode{name=US,quantity=8,at={[yshift=\vdist]CA.left},anchor=right} + \sankeynode{name=MX,quantity=8,at={[yshift=\vdist]US.left},anchor=right} + \sankeynode{name=BR,quantity=8,at={[yshift=\vdist]MX.left},anchor=right} + + \foreach \country in {CA,US,MX,BR}{ + \sankeystart[color=\country]{\country} + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{CA}{1/CA-to-PT,1/CA-to-GB,5/CA-to-FR} + \sankeyfork{US}{1/US-to-PT,1/US-to-SP,5/US-to-GB,1/US-to-FR} + \sankeyfork{MX}{1/MX-to-PT,5/MX-to-SP,1/MX-to-GB,1/MX-to-FR} + \sankeyfork{BR}{5/BR-to-PT,1/BR-to-SP,1/BR-to-GB,1/BR-to-FR} + + \sankeynode{name=FR,quantity=11, + at={[xshift=\hdist]CA.right},anchor=right} + \sankeynode{name=GB,quantity=11, + at={[yshift=\vdist]FR.left},anchor=right} + \sankeynode{name=SP,quantity=7, + at={[yshift=\vdist]GB.left},anchor=right} + \sankeynode{name=PT,quantity=8, + at={[yshift=\vdist]SP.left},anchor=right} + + \sankeyfork{FR} + {1/FR-from-BR,1/FR-from-MX,1/FR-from-US,5/FR-from-CA,3/FR-from-00} + \sankeyfork{GB} + {1/GB-from-BR,1/GB-from-MX,5/GB-from-US,1/GB-from-CA,3/GB-from-00} + \sankeyfork{SP}{1/SP-from-BR,5/SP-from-MX,1/SP-from-US} + \sankeyfork{PT}{5/PT-from-BR,1/PT-from-MX,1/PT-from-US,1/PT-from-CA} + + \foreach \country in {FR,GB,SP,PT}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{FR}{1/FR-to-ZA,1/FR-to-AO,3/FR-to-MA,3/FR-to-SN,3/FR-to-ML} + \sankeyfork{GB}{7/GB-to-ZA,1/GB-to-AO,2/GB-to-MA,1/GB-to-SN} + \sankeyfork{SP}{1/SP-to-ZA,3/SP-to-MA,1/SP-to-SN,2/SP-to-00} + \sankeyfork{PT}{3/PT-to-ZA,2/PT-to-AO,1/PT-to-MA,1/PT-to-SN,1/PT-to-00} + + \sankeynode{name=ML,quantity=9, + at={[xshift=\hdist]FR.right},anchor=right} + \sankeynode{name=SN,quantity=9, + at={[yshift=\vdist]ML.left},anchor=right} + \sankeynode{name=MA,quantity=9, + at={[yshift=\vdist]SN.left},anchor=right} + \sankeynode{name=AO,quantity=9, + at={[yshift=\vdist]MA.left},anchor=right} + \sankeynode{name=ZA,quantity=12, + at={[yshift=\vdist]AO.left},anchor=right} + + \sankeyfork{ML}{3/ML-from-FR,6/Mail-from-00} + \sankeyfork{SN} + {1/SN-from-PT,1/SN-from-SP,1/SN-from-GB,3/SN-from-FR,3/SN-from-00} + \sankeyfork{MA}{1/MA-from-PT,3/MA-from-SP,2/MA-from-GB,3/MA-from-FR} + \sankeyfork{AO}{2/AO-from-PT,1/AO-from-GB,1/AO-from-FR,5/AO-from-00} + \sankeyfork{ZA}{3/ZA-from-PT,1/ZA-from-SP,7/ZA-from-GB,1/ZA-from-FR} + + \foreach \country in {ML,SN,MA,AO,ZA}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + } + + \sankeyfork{ML}{5/ML-to-CN,3/ML-to-JP,1/ML-to-IN} + \sankeyfork{SN}{5/SN-to-CN,3/SN-to-JP,1/SN-to-IN} + \sankeyfork{MA}{5/MA-to-CN,3/MA-to-JP,1/MA-to-IN} + \sankeyfork{AO}{5/AO-to-CN,3/AO-to-JP,1/AO-to-IN} + \sankeyfork{ZA}{5/ZA-to-CN,3/ZA-to-JP,1/ZA-to-IN,3/ZA-to-00} + + \sankeynode{name=IN,quantity=5, + at={[xshift=\hdist]ML.right},anchor=right} + \sankeynode{name=JP,quantity=15, + at={[yshift=\vdist]IN.left},anchor=right} + \sankeynode{name=CN,quantity=25, + at={[yshift=\vdist]JP.left},anchor=right} + + \sankeyfork{IN} + {1/IN-from-ZA,1/IN-from-AO,1/IN-from-MA,1/IN-from-SN,1/IN-from-ML} + \sankeyfork{JP} + {3/JP-from-ZA,3/JP-from-AO,3/JP-from-MA,3/JP-from-SN,3/JP-from-ML} + \sankeyfork{CN} + {5/CN-from-ZA,5/CN-from-AO,5/CN-from-MA,5/CN-from-SN,5/CN-from-ML} + + \foreach \country in {IN,JP,CN}{ + \sankeyadvance[color=\country]{\country}{\hwidth} + \sankeyend[color=\country]{\country} + } + + \foreach \startcountry/\countries in { + CA/{PT,GB,FR}, US/{PT,SP,GB,FR}, MX/{PT,SP,GB,FR}, + BR/{PT,SP,GB,FR}, FR/{ML,SN,MA,AO,ZA}, GB/{SN,MA,AO,ZA}, + SP/{SN,MA,ZA}, PT/{SN,MA,AO,ZA}, ML/{IN,JP,CN}, + SN/{IN,JP,CN}, MA/{IN,JP,CN}, AO/{IN,JP,CN}, + ZA/{IN,JP,CN}} + { + \foreach \endcountry in \countries { + \sankeyoutin[shade={\startcountry}{\endcountry}] + {\startcountry-to-\endcountry}{\endcountry-from-\startcountry} + } + } + + + \foreach \country/\countryname in {CA/Canada, US/USA, MX/Mexico, + BR/Brazil, FR/France, GB/England, SP/Spain, PT/Portugal} + { + \node[anchor=south,inner sep=.1em,font=\small] + at (\country) {\countryname\vphantom{Ag}}; + } + + \foreach \country/\countryname in { + ML/Mali, SN/Senegal, MA/Morocco, AO/Angola, + ZA/South Africa, IN/India, JP/Japan, CN/China} + { + \node[anchor=south,inner sep=.1em,font=\small] + at (\country) {\countryname\vphantom{Ag}}; + } + \end{sankeydiagram} +\end{tikzpicture} +%</example3-variation> +% \fi +% +%^^A % ------------------------------------------------------------ +% \clearpage +% \section{Very nice example -- Nadieh Bremer creation} +%^^A % ------------------------------------------------------------ +% +% \embedfile[mimetype=text/plain]{sankey-example4.tex} +% +% \begin{figure} +% \centering +% {\MakePercentComment\input{sankey-example4}} +% \caption{Very nice example -- Nadieh Bremer's creation} +% (from +% \href{https://www.visualcinnamon.com/portfolio/adyen-report-2019/}{Adyen's +% Shareholder Report}) +% \label{fig:nice-example} +% \end{figure} +% +% Graphic designer Nadieh Bremer created this very nice Sankey +% diagram\footnote{\url{https://www.visualcinnamon.com/portfolio/adyen-report-2019/}} +% for Adyen's second half 2018 report to shareholders. It is coded here +% with her kind permission. +% +% You can change the data values between lines 28 and 53. +% +% See figure~\vref{fig:nice-example}. The \code{sankey-example4.tex} +% file contains the following code and is an attachement of the current +% PDF document. +% +% \lstinputlisting[numbers=left,style=LaTeXsmall]{sankey-example4} +% +% \iffalse +%<*example4> +\begin{tikzpicture} + \renewcommand*\sfdefault{txss} + \sffamily + \sisetup{ + detect-all=true, + group-separator={,}, + group-minimum-digits=4, + } + % storage of labels + \newcommand\LabSet[2]{% node name, label + \expandafter\edef\csname#1@Lab\endcsname{#2}} + \newcommand\Lab[1]{% node name + \csname#1@Lab\endcsname} + % storage of quantities + \newcommand\QtySet[2]{% node name, quantity + \expandafter\edef\csname#1@Qty\endcsname{\fpeval{#2}}} + \newcommand\Qty[1]{% node name + \csname#1@Qty\endcsname} + % all nodes with their name, label and quantity + \sankeyset{ + def data/.code args={#1/#2/#3}{% node name/label/values + \LabSet{#1}{#2} + \QtySet{#1}{#3} + \typeout{#1: \Qty{#1}€ (\Lab{#1})} + }, + def data/.list={ + {Pf/Processing\\fees/71713}, + {Sog/Sales of\\good/4547}, + {Sf/Settlement\\fees/842075}, + {Os/Other\\services/37532}, + {R/Revenues/\Qty{Pf}+\Qty{Sog}+\Qty{Sf}+\Qty{Os}}, + {Coi/Cost of Inventory/5151}, + {Ciffi/Cost insecure from financial institutions/758234}, + {Nr/Net revenue/\Qty{R}-\Qty{Coi}-\Qty{Ciffi}}, + {Aadotaifa/Amortization and\\depreciation of tangible and\\ + intangible fixed assets/4688}, + {Ssapc/Social securities and\\pension costs/7860}, + {Was/Wages and salaries/35627}, + {Ooe/Other operating expenses/37346}, + {Nr2/-/\Qty{Nr}-\Qty{Aadotaifa}-\Qty{Ssapc}-\Qty{Was}-\Qty{Ooe}}, + {Oi/Other income/47}, + {Ibiiieait/Income before interest income,\\interest expense and + income taxes/\Qty{Nr2}+\Qty{Oi}}, + {Fe/Finance expense/561}, + {Ofr/Other financial results/2533}, + {Ibiiieait2/-/\Qty{Ibiiieait}-\Qty{Fe}-\Qty{Ofr}}, + {Fi/Finance income/204}, + {Ibit/Income before income taxes/\Qty{Ibiiieait2}+\Qty{Fi}}, + {It/Income taxes/21134}, + {Niftp/Net income for the period/\Qty{Ibit}-\Qty{It}}, + {Octa/Other currency\\translation adjustments/785}, + {Tci/Total comprehensive income/\Qty{Niftp}+\Qty{Octa}} + }, + } + + \definecolor{mygreen}{RGB}{9,192,82} + \tikzset{ + cost node/.style={ + overlay, + align=flush center, + node font=\footnotesize\sffamily\bfseries, + inner sep=0, + node contents={% + {\mdseries€\,\num{\Qty{#1}}}\\ + \Lab{#1}\vphantom{g}% + }, + }, + white hash/.style={ + draw=none,fill=none, + pattern={Lines[angle=60,line width=2pt,distance=4pt]}, + pattern color=white, + }, + line sep/.style={draw=white,line width=1pt}, + left label/.style={left=#1,align=flush right,anchor=north east}, + right label/.style={right=#1,align=flush left}, + right label hashed/.style={ + right=1mm of $(#1.left)!.5!(#1-old.left)$,align=flush left, + }, + left label hashed/.style={ + left=1mm of $(#1.right)!.5!(#1-old.right)$,align=flush right, + }, + } + + \newcommand\turnandstop[1]{ + \sankeyturn[green to greenwhite]{#1}{-90} + \sankeynode{as=#1,name=#1-e,at={#1 -| Coi}} + \sankeyoutin[greenwhite to white]{#1}{#1-e} + \node[cost node=#1,left label={1mm of #1-e.right}]; + } + + \begin{sankeydiagram}%[debug] + \sankeyset{ + ratio=28em/1000000, + minimum radius=2cm, + start style=none, + every node/.style={angle=-90}, + % default fill and draw styles + fill/.style={ + line width=0pt, + fill=mygreen, + }, + draw/.style={draw=none}, + % specific fill and draw styles + green to greenwhite/.style={ + fill/.style={ + line width=0pt, + right color=mygreen, + left color=mygreen!20!white, + } + }, + greenwhite to white/.style={ + fill/.style={ + line width=0pt, + right color=mygreen!20!white, + left color=mygreen!5!white, + } + }, + dashed/.style={draw/.style={draw=mygreen,dashed}}, + } + + \coordinate (top) at (0,2em); + + \sankeynodestart{name=Pf,quantity=\Qty{Pf}} + \node[cost node=Pf,above=.5em of Pf.center]; + + \sankeynodestart{name=Sog,quantity=\Qty{Sog}, + at={[xshift=4em]Pf.left},anchor=right} + \node[cost node=Sog,above=.5em of Sog.center]; + + \sankeynodestart{name=Sf,quantity=\Qty{Sf}, + at={[xshift=2em]Sog.left},anchor=right} + \node[cost node=Sf,above=.5em of Sf.center]; + + \sankeynodestart{name=Os,quantity=\Qty{Os}, + at={[xshift=2em]Sf.left},anchor=right} + \node[cost node=Os,above=.5em of Os.center]; + + \sankeynode{ + name=R,quantity=\Qty{R},at={[yshift=-10em]Sf.center}, + forked={\Qty{Os}/Os-a,\Qty{Sf}/Sf-a,\Qty{Sog}/Sog-a,\Qty{Pf}/Pf-a}, + } + + \foreach \nodename in {Pf,Sog,Sf,Os}{ + \sankeyoutin[fill/.style={top color=white,bottom color=mygreen}] + {\nodename}{\nodename-a} + } + + \sankeyadvance{R}{1em} + \node[cost node=R,right label hashed=R]; + + \sankeyfork{R}{\Qty{Ciffi}/Ciffi,\Qty{Nr}/Nr,\Qty{Coi}/Coi} + + \sankeyturnleft[minimum radius=1.cm]{Ciffi}{90} + \node[cost node=Ciffi,at={([shift={(1mm,0)}]Ciffi.center)},rotate=-90, + anchor=south,align=flush left,node font=\scriptsize\sffamily\bfseries]; + + \sankeyturnright[green to greenwhite]{Coi}{90} + \sankeyadvance[greenwhite to white]{Coi}{1em} + \node[cost node=Coi,left={1mm of [yshift=.75ex]Coi.left}, + align=flush right,anchor=north east,overlay]; + + \sankeyadvance{Nr}{9em} + \sankeyadvance{Nr}{1em} + \node[cost node=Nr,left label hashed=Nr, + node font=\large\sffamily\bfseries]; + + \sankeyfork{Nr}{\Qty{Nr2}/Nr2,\Qty{Ooe}/Ooe, + \Qty{Was}/Was,\Qty{Ssapc}/Ssapc,\Qty{Aadotaifa}/Aadotaifa} + + \turnandstop{Aadotaifa} + + \sankeyadvance{Ssapc}{5em} + \turnandstop{Ssapc} + + \sankeyadvance{Was}{9em} + \turnandstop{Was} + + \sankeyadvance{Ooe}{12em} + \turnandstop{Ooe} + + \sankeyadvance{Nr2}{15em} + \sankeynode{name=Ibiiieait,quantity=\Qty{Ibiiieait}, + anchor=right,at={Nr2.right}, + forked={\Qty{Oi}/Oi,\Qty{Nr2}/Nr2-e}} + + \sankeyturnleftbackward[minimum radius=1cm,dashed]{Oi}{90} + \node[cost node=Oi,right label=1mm of Oi.left]; + + \sankeyadvance{Ibiiieait}{1em} + \node[cost node=Ibiiieait,right label hashed=Ibiiieait]; + + \sankeyfork{Ibiiieait} + {\Qty{Ibiiieait2}/Ibiiieait2,\Qty{Ofr}/Ofr,\Qty{Fe}/Fe} + + \turnandstop{Fe} + + \sankeyadvance{Ofr}{3em} + \turnandstop{Ofr} + + \sankeyadvance{Ibiiieait2}{6em} + \sankeynode{name=Ibit,quantity={\Qty{Ibiiieait2}+\Qty{Fi}}, + anchor=right,at={Ibiiieait2.right}, + forked={\Qty{Fi}/Fi,\Qty{Ibiiieait2}/Ibiiieait2-e}} + + \sankeyturnleftbackward[minimum radius=1cm,dashed]{Fi}{90} + \node[cost node=Fi,right label=1mm of Fi.left]; + + \sankeyadvance{Ibit}{1em} + \node[cost node=Ibit,right label hashed=Ibit]; + + \sankeyfork{Ibit}{\Qty{Niftp}/Niftp,\Qty{It}/It} + + \turnandstop{It} + + \sankeyadvance{Niftp}{6em} + + \sankeyadvance{Niftp}{1em} + \node[cost node=Niftp,right label hashed=Niftp]; + + \sankeynode{name=Tci,quantity=\Qty{Niftp}+\Qty{Octa}, + anchor=right,at={[yshift=-6em]Niftp.right}, + forked={\Qty{Octa}/Octa,\Qty{Niftp}/Niftp-e}} + \sankeyoutin{Niftp}{Niftp-e} + + \sankeyturnleftbackward[minimum radius=1cm]{Octa}{90} + \node[cost node=Octa,right label=1mm of Octa.left]; + + \sankeyadvance{Tci}{1em} + \node[cost node=Tci,right label hashed=Tci]; + + \newcommand\hashband[1]{ + \draw[line sep] (#1-old.right) -- (#1-old.left); + \draw[line sep] (#1.right) -- (#1.left); + \path[white hash] (#1-old.right) rectangle (#1.left); + } + + \foreach \nodename in {R,Nr,Nr,Ibiiieait,Ibit,Niftp,Tci}{ + \hashband{\nodename} + } + + \end{sankeydiagram} +\end{tikzpicture} +%</example4> +% \fi +% +% \clearpage +% +% \StopEventually{} +%^^A % ------------------------------------------------------------ +% +% \manualparts +% +% \part{Implementation} +% \label{implementation} +%^^A % ------------------------------------------------------------ +% +% { +% \setlength{\parskip}{0pt} +% \localtableofcontents +% } +% +%^^A % ------------------------------------------------------------ +% \section{The \texttt{sankey.sty} file} +%^^A % ------------------------------------------------------------ +% +% Poorly commented source code... +% +% \changes{v1.0}{2016/03/06}{first version} +% \changes{v2.0}{2021/01/27}{first public version (on CTAN)} +% \changes{v3.0}{2021/03/14}{better naming rule} +% \changes{v3.0}{2021/03/14}{use .ins and .dtx files} +% +% \iffalse +%<*sankey> +% \fi +% +% Version information: +% +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e}[2015/10/01] +\ProvidesPackage{sankey}[2021/03/14 v3.0 to draw Sankey diagrams] +% \end{macrocode} +% +% All required packages and TikZ libraries: +% \begin{macrocode} +\RequirePackage{xparse} +\RequirePackage{etoolbox} +\RequirePackage{xfp} +\RequirePackage{tikz} +\usetikzlibrary{ + calc, + decorations.markings, + dubins +} +% \end{macrocode} +% +% Declarations of PGF layers (to debug Sankey diagrams): +% +% \begin{macrocode} +%% add a new layer to debug sankey diagrams +\pgfdeclarelayer{background} +\pgfdeclarelayer{foreground} +\pgfdeclarelayer{sankeydebug} +\pgfsetlayers{background,main,foreground,sankeydebug} +% \end{macrocode} +% +% +%^^A % ------------------------------------------------------------ +% \subsection{Fields} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@newfield} +% +% The \code{sankeynewfield} macro defines +% setter and getter macros for \emph{key}/\emph{value} pairs. +% It requires five parameters: the \emph{def} macro used to +% store a new value, the \emph{setter} macro name, the \emph{getter} macro name, +% the \emph{cs name} used by the new field (including a \texttt{\#1} +% parameter -- the \emph{key}) and the \emph{error message} (used by the getter +% macro if the key is not defined). +% +% The \emph{setter} macro requires +% two parameters: the key and the value. +% The \emph{getter} macro requires +% one parameter: the key. +% +% \begin{macrocode} +\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}% + }% + } +} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Definition of \emph{global} and \emph{expanded} fields (using +% \texttt{\protect\string\xdef})} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@setnodeqty} +% \begin{macro}{\sankeygetnodeqty} +% The setter and getter macros to store and retrieve +% the \emph{quantity} field associated with +% each Sankey node (the key is the name of the Sankey node). +% \begin{macrocode} +\snk@newfield\xdef\snk@setnodeqty\sankeygetnodeqty% +{@snk@node@qty@#1}{Unknown sankey node '#1'} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\snk@setnodeorient} +% \begin{macro}{\sankeygetnodeorient} +% The setter and getter macros to store and retrieve +% the \emph{angle} (or orientation) field +% associated with each Sankey node (the key is the name of the Sankey node). +% \begin{macrocode} +\snk@newfield\xdef\snk@setnodeorient\sankeygetnodeorient% +{@snk@node@orient@#1}{Unknown sankey node '#1'} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Definitions of \emph{local} fields (using \texttt{\protect\string\def})} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@setstartfill} +% \begin{macro}{\snk@getstartfill} +% \begin{macro}{\snk@setstartdraw} +% \begin{macro}{\snk@getstartdraw} +% The setter and getter macros to store and retrieve the starting fill/draw +% paths (the key is the style name). +% \begin{macrocode} +\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} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\snk@setendfill} +% \begin{macro}{\snk@getendfill} +% \begin{macro}{\snk@setenddraw} +% \begin{macro}{\snk@getenddraw} +% The setter and getter macros to store and retrieve the ending fill/draw +% paths (the key is the style name). +% \begin{macrocode} +\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} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Check if a sankey node is defined} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@ifnodedefined} + +% The \code{\snk@ifnodedefined} macro checks if a Sankey +% node is defined by checking if its name is associated to +% a \emph{quantity}. +% \begin{macrocode} +\newcommand\snk@ifnodedefined[3]{% + \ifcsdef{@snk@node@qty@#1}{#2}{#3}% +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@errorifnotdefined} +% The \code{\snk@errorifnotdefined} macro generares +% an error message if the Sankye node is not defined. +% \begin{macrocode} +\newcommand\snk@errorifnotdefined[1]{% + \snk@ifnodedefined{#1}{}% + {\PackageError{sankey}{Unknown sankey node '#1'}{}}% +} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsection{The \texttt{sankey node} shape} +%^^A % ------------------------------------------------------------ +% +% +% A \code{sankey node} is defined as a TikZ node +% with a particular \emph{shape}: its width is null and its +% height matches the associated \emph{quantity}. +% This shape requires only three anchors: \code{center}, \code{left} +% and \code{right}. +% These threee anchors are sufficient to use the +% \code{sankey} package. But the \code{fit} library needs +% anchors defined by rectangular node. +% +% \begin{macrocode} +\pgfdeclareshape{sankey node}{ + \inheritsavedanchors[from=rectangle] + \inheritanchor[from=rectangle]{center} + \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} +} +% \end{macrocode} +% +%^^A % ------------------------------------------------------------ +% \subsection{Keys} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\sankeyset} +% The \code{sankey} package uses \code{pgfkeys} to set options via +% \emph{key=value} pairs using the \texttt{/sankey} path +% (for Sankey diagram options) and using the +% \texttt{/sankey/node parameters} path (for Sankey node parameters). +% +% The \code{\sankeyset} macro processes +% its parameter as a list of comma separated pairs of the form +% \emph{key=value} with the default path set to \texttt{/sankey}. +% +% \begin{macrocode} +\pgfkeys{/sankey/.is family} +\NewDocumentCommand\sankeyset{m}{\pgfkeys{sankey,#1}} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Keys to define the scale} +%^^A % ------------------------------------------------------------ +% \begin{macro}{\snk@totalqty} +% \begin{macro}{\snk@totallen} +% +% The \code{ratio quantity}, \code{ratio length} and +% \code{ratio} keys define the ratio between +% \emph{flow quantity} and \emph{graphic length} (the scale). +% The \code{\snk@totalqty} and \code{\snk@totallen} macros store the values. +% All \emph{quantities} are processed by \code{\fpeval} and +% all \emph{lengths} are processed by \code{pgfmath}. +% \begin{macrocode} +\sankeyset{ + ratio quantity/.code={\edef\snk@totalqty{\fpeval{#1}}}, + ratio quantity/.value required, + ratio length/.code={ + \pgfmathsetmacro\snk@totallen{#1} + \edef\snk@totallen{\snk@totallen pt} + }, + ratio length/.value required, + ratio/.style args={#1/#2}{ + ratio length=#1, + ratio quantity=#2, + }, + ratio/.value required, +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Rotate offset} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@rotate} +% +% The \code{rotate} key stores an offset angle applied to all Sankey +% nodes. This is useful when using the \code{rotate} option within a +% \code{tikzpicture} or a \code{scope}. This TikZ option is only +% applied to coordinates and not to TikZ nodes (remember that Sankey +% nodes are TikZ nodes). It's up to the author to keep the +% \code{rotate} option of the \code{tikzpicture} and that of the +% \code{sankeydiagram} synchronous. +% +% \begin{macrocode} +\sankeyset{ + rotate/.code={\edef\snk@rotate{\fpeval{#1}}}, + rotate/.value required, +} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Minimum radius} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@minradius} +% +% The \code{minimum radius} key processes the minimum radius +% of curvature by \code{pgfmath} then stores it in +% the \code{\snk@minradius} macro. +% \begin{macrocode} +\sankeyset{ + minimum radius/.code={ + \pgfmathsetmacro\snk@minradius{#1} + \edef\snk@minradius{\snk@minradius pt} + }, + minimum radius/.value required, +} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Outin step} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@stepoutin} +% The \code{outin} key stores its value in +% the \code{\snk@stepoutin} macro. +% +% \begin{macrocode} +\sankeyset{ + outin steps/.estore in=\snk@stepoutin, + outon steps/.value required, +} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Sankey debug} +%^^A % ------------------------------------------------------------ +% +% +% The \code{debug} key drives the \code{sankey debug} toggle. +% +% \begin{macrocode} +\newtoggle{sankey debug} +\sankeyset{ + debug/.is choice, + debug/true/.code={\toggletrue{sankey debug}}, + debug/false/.code={\togglefalse{sankey debug}}, + debug/.default=true, +} +% \end{macrocode} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Start and end styles} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@startstyle} +% \begin{macro}{\snk@endstyle} +% The \code{start style} and \code{end style} keys are choices. +% +% The \code{new start style} and \code{new end style} keys +% add new option to these choices. +% They use the \code{startfill}, \code{startdraw} fields +% or the \code{endfill} and \code{enddraw} +% fields (using the style \emph{name} as key) to store the fill and draw +% paths then create a new option to install the new +% start (\code{\snk@startstyle}) or end (\code{\snk@endstyle}) style. +% +% \begin{macrocode} +\sankeyset{ + start style/.is choice, + end style/.is choice, + % 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}}} + }, +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Initial parameters} +%^^A % ------------------------------------------------------------ +% +% The \code{@initial options} style defines default values for +% options of Sankey diagram. The \code{every diagram} style (initially +% empty) allows the user to choose its own default values. +% +% The \code{@initial options} and the \code{every diagram} styles are +% applied (in this order) at the beginning of each Sankey diagram. +% +% \begin{macrocode} +\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, + 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}, + }, + every node/.style={}, + }, + every diagram/.style={}, +} + +% \end{macrocode} +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Sankey node parameters} +%^^A % ------------------------------------------------------------ +% +% The \code{/sankey/node parameters} family defines all parameters during +% creation of Sankey node. +% +% \begin{macrocode} +\sankeyset{node parameters/.is family} +% \end{macrocode} +% \begin{macro}{\name} +% \begin{macro}{\qty} +% \begin{macro}{\orient} +% \begin{macro}{\pos} +% +% The \code{name}, \code{quantity}, \code{angle} and \code{at} keys use the +% \code{\name}, \code{\qty}, \code{\orient} and \code{\pos} macros +% to store the \emph{name}, the \emph{quantity}, the \emph{orientation} (or +% \emph{angle}) and the \emph{position} of a Sankey node during its +% creation. +% +% The \emph{quantity} is processed via \code{\fpeval}. The +% \emph{orientation} is normalized. +% +% \begin{macrocode} +\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, +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% The \code{as} key is just a shortcut to define the four current node +% parameters by copying them from an existing Sankey node. +% +% \begin{macrocode} +\sankeyset{node parameters, + as/.style={ + name=#1, + quantity=\sankeygetnodeqty{#1}, + angle=\sankeygetnodeorient{#1}, + at={#1.center}, + }, + as/.value required, +} +% \end{macrocode} +% +% \begin{macro}{\snk@anchor} +% +% The \code{anchor} key stores in the \code{\snk@anchor} macro +% the anchor name to use to create the new current Sankey node +% +% \begin{macrocode} +\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, +} +% \end{macrocode} +% \end{macro} +% +% The \code{start} and \code{end} keys drive the +% \code{sankey node start} and \code{sankey node end} +% toggles. +% +% \begin{macrocode} +\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, +} +% \end{macrocode} +% \begin{macro}{\snk@listofforks} +% \begin{macro}{\snk@forkanchor} +% +% The \code{forked} and \code{fork anchor} keys store their value in the +% \code{\snk@listofforks} and \code{\snk@forkanchor} macros. +% +% \begin{macrocode} +\sankeyset{node parameters, + forked/.estore in=\snk@listofforks, + forked/.value required, + fork anchor/.estore in=\snk@forkanchor, + fork anchor/.value required, +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% The \code{@initial parameters} style initialises all Sankey node +% parameters at the start of the creation of a new Sankey node. +% +% \begin{macrocode} +\sankeyset{node parameters, + @initial parameters/.style={ + start=false, + end=false, + forked=, + fork anchor=, + anchor=center, + at={0,0}, + angle=0, + }, +} +% \end{macrocode} +% +% +%^^A % ------------------------------------------------------------ +% \subsubsection{Internal Tikz style} +%^^A % ------------------------------------------------------------ +% +% To apply this style with Tikz, use absolute key name +% (\texttt{/sankey/@sankey node}). This style is used to create the Tikz +% node assoicated to a Sankey node. +% +% \begin{macrocode} +\sankeyset{ + % 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, + }, +} +% \end{macrocode} +% +%^^A % ------------------------------------------------------------ +% \subsection{The \texttt{sankeydiagram} environment} +% ^^A % ------------------------------------------------------------ +% +% \begin{environment}{sankeydiagram} +% +% The \code{sankeydiagram} environment defines locally all the macros +% used by a Sankey diagram. Then it applies the % +% \code{@initial options} and \code{every diagram} styles (in this +% order) and applies all the keys provided in its optional argument. +% +% \begin{macrocode} +\NewDocumentEnvironment{sankeydiagram}{O{}}{ +% \end{macrocode} +% +%^^A % ------------------------------------------------------------ +% \subsection{Internal macros} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\snk@getpos} +% +% The \code{\snk@getpos} macro extracts the position of a TikZ +% node\footnote{Thanks to Andrew Stacey \url{https://tex.stackexchange.com/a/33765/14500}}. +% +% \begin{macrocode} + \def\snk@getpos##1##2{% + \tikz@scan@one@point\pgfutil@firstofone(##2)\relax% + \edef##1{\the\pgf@x,\the\pgf@y}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@modulo} +% +% The \code{\snk@modulo} macro evaluates \#1 modulo \#2 using \code{\fpeval}. +% +% \begin{macrocode} + \def\snk@modulo##1##2{\fpeval{##1-(floor((##1)/(##2),0)*##2)}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@normalize@angle} +% +% The \code{\snk@normalize@angle} macro normalizes \#1 (an angle) between +% $-180$ and $180$ (using \code{\fpeval}). +% +% \begin{macrocode} + \def\snk@normalize@angle##1{% + \fpeval{\snk@modulo{(##1)+180}{360}-180}% + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@show@debug} +% +% The \code{snk@show@debug} macro draws debug information +% of the Sankey node named \#1 but only if the \code{sankey debug} +% toogle is true. Everything is drawn on the \code{sankeydebug} +% layer. It uses the \code{/sankey/debug line}, +% \code{/sankey/debug normal} and \code{/sankey/debug label} Tikz styles. +% +% \begin{macrocode} + \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} + \path[/sankey/debug line] (\name.left) -- (\name.right); + \pgfmathsetmacro{\snk@len}{\sankeyqtytolen{\qty}/3} + \path[/sankey/debug normal] (\name.center) + -- ($(\name.center)!\snk@len pt!90:(\name.right)$) + node[/sankey/debug label,rotate=\orient+90+\snk@rotate,anchor=north]; + \end{pgfonlayer} + \endgroup + }{} + } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\snk@makeforkednode} +% \begin{macro}{\snk@tot} +% \begin{macro}{\snk@subnodeqty} +% \begin{macro}{\snk@subnodename} +% \begin{macro}{\snk@added@values} +% +% The \code{\snk@makeforkednode} forks a Sankey node. +% +% \begin{macrocode} + \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 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\snk@makenode} +% +% The \code{\snk@makenode} macro creates a new Sankey node named +% \code{\name} with \code{\qty} quantity, oriented at +% \code{\orient} degrees (but modified by the \code{\snk@rotate} +% angle offset), anchored by its \code{\anchor} (or its \emph{center} +% by default) at \code{\pos} position. +% +% \begin{macrocode} + \def\snk@makenode{ + \begingroup + \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 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@filldrawstart} +% +% The \code{\snk@filldrawstart} macro fills +% (with the \code{/sankey/fill} TikZ style) then draws +% (with the \code{/sankey/draw} TikZ style) +% a start of flow using paths from style \code{\snk@startstyle} on +% the Sankey node named \code{\name}. +% +% \begin{macrocode} + \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} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@filldrawend} +% +% The \code{\snk@filldrawend} macro fills +% (with the \code{/sankey/fill} TikZ style) then draws +% (with the \code{/sankey/draw} TikZ style) +% a end of flow using paths from style \code{\snk@endstyle} on +% the Sankey node named \code{\name}. +% +% \begin{macrocode} + \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} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\snk@checkquantities} +% \begin{macro}{\snk@qtyi} +% \begin{macro}{\snk@qtyii} +% The \code{\snk@checkquantities} compares quantities +% from Sankey nodes \code{#1} and \code{#2} and emits +% an error message if they differ (\code{#3} is the name +% of the macro which requested the verification). +% +% \begin{macrocode} + \def\snk@checkquantities##1##2##3{ + \begingroup + \edef\snk@qtyi{\sankeygetnodeqty{##1}} + \edef\snk@qtyii{\sankeygetnodeqty{##2}} + \ifdefstrequal{\snk@qtyi}{\snk@qtyii}{}{ + \PackageError{sankey}% + {^^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 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsection{User macros} +%^^A % ------------------------------------------------------------ +% +% \begin{macro}{\sankeydubins} +% +% The \code{\sankeydubins} macro links two Sankey nodes via +% a Dubins path. First, it computes the Dubins path between +% centers (left and right radii are the same) and stores the +% result in \code{sankey}. Then it uses the stored result +% to fill and draw the lane (left border and right borders +% use Dubins paths with asymmetric radii). +% +% \begin{macrocode} + \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}} + \dubinspathset{ + sankey/.style={ + 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={\snk@minradius} + and {\snk@minradius + \sankeyqtytolen{\qty} pt}, + }, + right border/.style={ + sankey, use store=sankey, + left and right minimum radii= + {\snk@minradius + \sankeyqtytolen{\qty} pt} + and {\snk@minradius}, + }, + } + % 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 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeyoutin} +% +% The \code{\sankeyoutin} macro links two Sankey nodes via a Bézier curve. +% First, to simulate constant width, it creates \code{\snk@stepoutin} +% intermediate Sankey nodes along the Bézier curve. Then, the lane is +% filled and drawn linking all the intermediate Sankey node via smaller +% Bézier curves. +% +% \begin{macrocode} + \NewDocumentCommand\sankeyoutin{O{}mm}{% options, sn, en + \snk@errorifnotdefined{##2} + \snk@errorifnotdefined{##3} + \snk@checkquantities{##2}{##3}{\sankeyoutin} + \begingroup + \sankeyset{##1} + \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 \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(\snk@outinmidptname) + (0,-\snk@len pt) coordinate (\snk@outinmidptname-r) + (0,\snk@len pt) coordinate (\snk@outinmidptname-l) + ; + } + }] + (##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}% + } + \path[/sankey/fill,looseness=1] + (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) + } + -- cycle; + \path[/sankey/draw,looseness=1] + (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 + } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\sankeynodealias} +% +% The \code{\sankeynodealias} macro clones the Sankey node +% named \code{#1} into a Sankey node named \code{#2}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeynodealias{mm}{%name, alias + \snk@errorifnotdefined{##1} + \path[late options={name=##1,alias=##2}]; + \snk@setnodeqty{##2}{\sankeygetnodeqty{##1}} + \snk@setnodeorient{##2}{\sankeygetnodeorient{##1}} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeynode} +% +% The \code{\sankeynode} macro creates the new Sankey +% node named \code{#2}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeynode{O{}m}{% options, node parameters + \begingroup + \sankeyset{##1} + \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 + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeystart} +% +% The \code{\sankeystart} macro fills and draws a starting lane +% attached to the Sankey node named \code{#2}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeystart{O{}m}{% options, name + \snk@errorifnotdefined{##2} + \begingroup + \sankeyset{##1} + \edef\name{##2} + \edef\orient{\sankeygetnodeorient{##2}} + \edef\qty{\sankeygetnodeqty{##2}} + \snk@filldrawstart + \endgroup + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeynodestart} +% +% The \code{\sankeynodestart} macro creates the new Sankey +% node named \code{#2} then fills and draws a starting lane +% attached to this new Sankey node. +% +% \begin{macrocode} + \NewDocumentCommand\sankeynodestart{O{}m}{% option, node parameters + \sankeynode[##1]{start,##2} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeyend} +% +% The \code{\sankeyend} macro fills and draws an ending lane +% attached to the Sankey node named \code{#2}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeyend{O{}m}{%options, name + \snk@errorifnotdefined{##2} + \begingroup + \sankeyset{##1} + \edef\name{##2} + \edef\orient{\sankeygetnodeorient{##2}} + \edef\qty{\sankeygetnodeqty{##2}} + \snk@filldrawend + \endgroup + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeynodeend} +% +% The \code{\sankeynodeend} macro creates the new Sankey +% node named \code{#2} then fills and draws an ending lane +% attached to this new Sankey node. +% +% \begin{macrocode} + \NewDocumentCommand\sankeynodeend{O{}m}{% options, node parameters + \sankeynode[##1]{end,##2} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\sankeyadvance} +% \begin{macro}{\sankeyadvance*} +% +% The \code{\sankeyadvance} macro moves toward (or backward if +% \emph{starred} calls -- \code{#1}) the Sankey node named \code{#3}. +% \code{#4} is a distance. The previous position is keeped +% by a Sankey node named \code{#3-old}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeyadvance{sO{}mm}{% + %params: *(reverse), options, name, distance + \snk@errorifnotdefined{##3} + \begingroup + \sankeyset{##2} + \edef\name{##3} + \edef\snk@oldname{##3-old} + \sankeynodealias{\name}{\snk@oldname} + \IfBooleanTF{##1}{ + % move backward + \sankeynode{ + at={$(\snk@oldname.center)!##4!90:(\snk@oldname.left)$}, + angle=\sankeygetnodeorient{\snk@oldname}, + quantity=\sankeygetnodeqty{\snk@oldname}, + name=\name, + } + \path[/sankey/fill] + (\name.left) -- (\snk@oldname.left) + -- (\snk@oldname.right) -- (\name.right) -- cycle; + \path[/sankey/draw] + (\name.left) -- (\snk@oldname.left) + (\snk@oldname.right) -- (\name.right); + }{ + % move forward + \sankeynode{ + at={$(\snk@oldname.center)!##4!-90:(\snk@oldname.left)$}, + angle=\sankeygetnodeorient{\snk@oldname}, + quantity=\sankeygetnodeqty{\snk@oldname}, + name=\name, + } + \path[/sankey/fill] + (\snk@oldname.left) -- (\name.left) + -- (\name.right) -- (\snk@oldname.right) -- cycle; + \path[/sankey/draw] + (\snk@oldname.left) -- (\name.left) + (\name.right) -- (\snk@oldname.right); + } + \snk@show@debug{\name} + \endgroup + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\sankeyturnright} +% \begin{macro}{\sankeyturnright*} +% +% \changes{v3.0}{2021/03/14}{new macro} +% +% The \code{sankeyturnright} macro moves forward the Sankey node +% named \code{#3} by turning right. The angle is \code{#4} (the starred +% version uses the opposite of \code{#4}). If the angle is \emph{negative}, the +% macro calls the \code{\sankeyturnrightbackward} macro to move backward else +% the macro fills/draws the lane between the previous position and the new +% position. The previous position is keeped by a Sankey +% node named \code{#3-old}. +% +% \begin{macrocode} + \NewDocumentCommand\sankeyturnright{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=(\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} + }{ + \sankeyturnrightbackward[##2]{##3}{-1*\snk@angle} + } + \endgroup + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\sankeyturnrightbackward} +% \begin{macro}{\sankeyturnrightbackward*} +% +% \changes{v3.0}{2021/03/14}{new macro} +% +% The \code{sankeyturnrightbackward} macro moves backward the Sankey node +% named \code{#3} by turning right. The angle is \code{#4} (the starred +% version uses the opposite of \code{#4}). If the angle is \emph{negative}, the +% macro calls the \code{\sankeyturnright} macro to move forward else +% the macro fills/draws the lane between the previous position and the new +% position. The previous position is keeped by a Sankey +% node named \code{#3-old}. +% +% \begin{macrocode} + \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} + } + \endgroup + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\sankeyturnleft} +% \begin{macro}{\sankeyturnleft*} +% +% \changes{v3.0}{2021/03/14}{new macro} +% +% The \code{sankeyturnleft} macro moves forward the Sankey node +% named \code{#3} by turning left. The angle is \code{#4} (the starred +% version uses the opposite of \code{#4}). If the angle is \emph{negative}, the +% macro calls the \code{\sankeyturnleftbackward} macro to move backward else +% the macro fills/draws the lane between the previous position and the new +% position. The previous position is keeped by a Sankey +% node named \code{#3-old}. +% +% \begin{macrocode} + \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 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\sankeyturnleftbackward} +% \begin{macro}{\sankeyturnleftbackward*} +% +% \changes{v3.0}{2021/03/14}{new macro} +% +% The \code{sankeyturnleftbackward} macro moves backward the Sankey node +% named \code{#3} by turning left. The angle is \code{#4} (the starred +% version uses the opposite of \code{#4}). If the angle is \emph{negative}, the +% macro calls the \code{\sankeyturnleft} macro to move forward else +% the macro fills/draws the lane between the previous position and the new +% position. The previous position is keeped by a Sankey +% node named \code{#3-old}. +% +% \begin{macrocode} + \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 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\sankeyturn} +% \begin{macro}{\sankeyturn*} +% +% \changes{v3.0}{2021/03/14}{simplification by using new \emph{turn} macros} +% +% The \code{\sankeyturn} macro moves toward (or backward if +% \emph{starred} calls -- \code{#1}) the Sankey node named +% \code{#3} by turning left (angle \code{#4} is positive) +% or right (angle \code{#4} is negative). +% The previous position is keeped by a Sankey node named +% \code{#3-old}. +% +% \begin{macrocode} + \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 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \begin{macro}{\sankeyfork} +% +% The \code{\sankeyfork} macro forks the Sankey node named +% \code{#2} to the list of subnodes given by \code{#3}. +% The subnodes are cloned to take into account +% the \code{debug} option. +% +% \begin{macrocode} + \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 + } +% \end{macrocode} +% \end{macro} +% \begin{macro}{\sankeyqtytolen} +% +% The \code{\sankeyqtytolen} macro converts quantity +% to length using \code{\fpeval} and the ratio determined +% by \code{\snk@totalqty} and \code{sankeytotallen}. +% +% \begin{macrocode} + \def\sankeyqtytolen##1{\fpeval{(##1)/\snk@totalqty*\snk@totallen}} +% \end{macrocode} +% \end{macro} +% +%^^A % ------------------------------------------------------------ +% \subsection{The \protect\texttt{sankeydiagram} environment (the end)} +%^^A % ------------------------------------------------------------ +% +% Here is the end of the definition of the \code{sankeydiagram} +% environment. The \code{@initial options} style and the % +% \code{every diagram} style are applied before options provided by +% user. +% +% \begin{macrocode} + \sankeyset{ + @initial options, + every diagram, + % user values + #1} +} +{} % empty but mandatory ! :-) +% \end{macrocode} +% \end{environment} +% +%^^A % ------------------------------------------------------------ +% \subsection{Predefined start and end styles} +%^^A % ------------------------------------------------------------ +% +% The \code{none} style. +% +% \begin{macrocode} +\sankeyset{ + new start style={none}{}{}, + new end style={none}{}{}, +} +% \end{macrocode} +% +% The \code{simple} style. +% +% \begin{macrocode} +\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) + }, + new end style={simple}{ + (\name.left) -- ([xshift=2mm]\name.center) + -- (\name.right) -- cycle + }{ + (\name.left) -- ([xshift=2mm]\name.center) -- (\name.right) + }, +} +% \end{macrocode} +% +% The \code{arrow} style. +% +% \begin{macrocode} +\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) + }, + 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) + }, +} +% \end{macrocode} +% \iffalse +%</sankey> +% \fi +% +%^^A % ------------------------------------------------------------ +% \section{\texttt{tikzlibrarydubins.code.tex}} +%^^A % ------------------------------------------------------------ +% +% Not yet documented nor commented... +% +% \iffalse +%<*tikzlibrarydubins.code.tex> +% \fi +% \begin{macrocode} +\def\tikzlibrarydubins@version{v3.0} +\def\tikzlibrarydubins@date{2021/03/14} + +\usetikzlibrary{calc} +\RequirePackage{etoolbox} +\RequirePackage{xfp} + +\newbool{dubinspathreverse} + +\def\ifpgfmathcond#1{% + \pgfmathparse{(#1)?1:0}% + \ifnumequal{\pgfmathresult}{1}% +} + + +\def\dbp@getxy#1#2#3{% + \tikz@scan@one@point\pgfutil@firstofone(#3)\relax% + \edef#1{\the\pgf@x}% + \edef#2{\the\pgf@y}% +} + +\def\dbp@anglebetween#1#2#3{%macro, s, t + \dbp@getxy\dbp@ax\dbp@ay{#2} + \dbp@getxy\dbp@bx\dbp@by{#3} + \pgfmathsetmacro#1{atan2(\dbp@by-\dbp@ay,\dbp@bx-\dbp@ax)} +} + +\def\dbp@distancebetween#1#2#3{%macro, s, t + \dbp@getxy\dbp@ax\dbp@ay{#2} + \dbp@getxy\dbp@bx\dbp@by{#3} + \edef#1{\fpeval{sqrt(% + (\dbp@bx-\dbp@ax)*(\dbp@bx-\dbp@ax)% + +(\dbp@by-\dbp@ay)*(\dbp@by-\dbp@ay)% + )}}% +} + +\newcommand\dbp@rsr{% s, sa, t, ta, as, len, at, r + let + \p{tr}=([shift={(\dbp@angb-90:\dbp@radius pt)}]\dbp@b), + \n1={\dbp@anga+90}, + \n2={\dbp@angb+90}, + \n3={\n2+\dbp@lastangle} + in + arc(\n1:\n1-\dbp@firstangle:\dbp@rradius pt) + -- ([shift={(\p{tr})}]\n3:\dbp@rradius pt) + arc(\n3:\n2:\dbp@rradius pt) +} + +\newcommand\dbp@lsl{% s, sa, t, ta, as, len, at, r + let + \p{tl}=([shift={(\dbp@angb+90:\dbp@radius pt)}]\dbp@b), + \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, + \n3={\dbp@angb-90},\n4={\n3-\dbp@lastangle} + in + arc(\n1:\n2:\dbp@lradius pt) + -- ([shift={(\p{tl})}]\n4:\dbp@lradius pt) + arc(\n4:\n3:\dbp@lradius pt) +} + +\newcommand\dbp@rsl{% s, sa, t, ta, as, len, at, r + let + \p{tl}=([shift={(\dbp@angb+90:\dbp@radius pt)}]\dbp@b), + \n1={\dbp@anga+90},\n2={\n1-\dbp@firstangle}, + \n3={\dbp@angb-90},\n4={\n3-\dbp@lastangle} + in + arc(\n1:\n2:\dbp@rradius pt) + -- ([shift={(\p{tl})}]\n4:\dbp@lradius pt) + arc(\n4:\n3:\dbp@lradius pt) +} + +\newcommand\dbp@lsr{% s, sa, t, ta, as, len, at, r + let + \p{tr}=([shift={(\dbp@angb-90:\dbp@radius pt)}]\dbp@b), + \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, + \n3={\dbp@angb+90},\n4={\n3+\dbp@lastangle} + in + arc(\n1:\n2:\dbp@lradius pt) + -- ([shift={(\p{tr})}]\n4:\dbp@rradius pt) + arc(\n4:\n3:\dbp@rradius pt) +} + +\newcommand\dbp@lrl{% s, sa, t, ta, as, ai, at, r + let + \n1={\dbp@anga-90},\n2={\n1+\dbp@firstangle}, + \n3={\dbp@angb-90},\n4={\n3-\dbp@lastangle} + in + arc(\n1:\n2:\dbp@lradius pt) + arc(\n2+180:\n2+180-\dbp@midparam:\dbp@rradius pt) + arc(\n4:\n3:\dbp@lradius pt) +} + +\newcommand\dbp@rlr{% s, sa, t, ta, as, ai, at, r + let + \n1={\dbp@anga+90},\n2={\n1-\dbp@firstangle}, + \n3={\dbp@angb+90},\n4={\n3+\dbp@lastangle} + in + arc(\n1:\n2:\dbp@rradius pt) + arc(\n2+180:\n2+180+\dbp@midparam:\dbp@lradius pt) + arc(\n4:\n3:\dbp@rradius pt) +} +\newcommand\dbp@rev@lsl{\dbp@rsr} +\newcommand\dbp@rev@rsr{\dbp@lsl} +\newcommand\dbp@rev@lsr{\dbp@lsr} +\newcommand\dbp@rev@rsl{\dbp@rsl} +\newcommand\dbp@rev@lrl{\dbp@rlr} +\newcommand\dbp@rev@rlr{\dbp@lrl} + + +\newcommand\dubinspath[1]{% + \pgfextra{ + \dubinspathset{#1} + \ifbool{dubinspathreverse}{ + \edef\dbp@newa{\dbp@b} + \edef\dbp@newb{\dbp@a} + \pgfmathsetmacro\dbp@newanga{180+\dbp@angb} + \pgfmathsetmacro\dbp@newangb{180+\dbp@anga} + \edef\dbp@newfirstangle{\dbp@lastangle} + \edef\dbp@newlastangle{\dbp@firstangle} + \edef\dbp@newmethod{rev@\dbp@method} + \edef\dbp@newlradius{\dbp@rradius} + \edef\dbp@newrradius{\dbp@lradius} + \dubinspathset{ + start point=\dbp@newa, + end point=\dbp@newb, + start angle=\dbp@newanga, + end angle=\dbp@newangb, + first angle=\dbp@newfirstangle, + last angle=\dbp@newlastangle, + left and right minimum radii=\dbp@newlradius pt and \dbp@newrradius pt, + method=\dbp@newmethod, + } + }{} + } + \csname dbp@\dbp@method\endcsname% +} + + +%% solution + +\def\dbp@store#1#2{% + \expandafter\xdef\csname dbp@store@#1@#2\endcsname% + {\csname dbp@#2\endcsname}% +} +\def\dbp@get#1#2{% + \csname dbp@store@#1@#2\endcsname% +} + +\def\dbp@setparams#1#2#3#4#5{% + % method, length, fisrt angle, middle param, last angle + \edef\dbp@method{#1} + \edef\dbp@length{#2} + \edef\dbp@firstangle{#3} + \edef\dbp@middleparam{#4} + \edef\dbp@lastangle{#5} + \ifdef{\dbp@storename}{ + \foreach \p in {method,length,firstangle,middleparam,lastangle}{ + \dbp@store{\dbp@storename}{\p} + } + }{} +} + +\def\dbp@updateparams#1#2#3#4#5{ + \ifpgfmathcond{#2<\dbp@length}{ + \dbp@setparams{#1}{#2}{#3}{#4}{#5} + }{} +} + +\tikzset{ + dubins path/.is family, + dubins path, + start point/.store in=\dbp@a, + start angle/.store in=\dbp@anga, + end point/.store in=\dbp@b, + end angle/.store in=\dbp@angb, + store/.store in=\dbp@storename, + use store/.style={ + method=\dbp@get{#1}{method}, + first angle=\dbp@get{#1}{firstangle}, + last angle=\dbp@get{#1}{lastangle}, + middle param=\dbp@get{#1}{middleparam}, + }, + minimum radius/.code={ + \pgfmathsetmacro\dbp@radius{#1} + \pgfmathsetmacro\dbp@rradius{#1} + \pgfmathsetmacro\dbp@lradius{#1} + }, + left and right minimum radii/.code args={#1 and #2}{ + \pgfmathsetmacro\dbp@lradius{#1} + \pgfmathsetmacro\dbp@rradius{#2} + \pgfmathsetmacro\dbp@radius{(\dbp@lradius + \dbp@rradius)/2} + }, + method/.store in=\dbp@method, + first angle/.store in=\dbp@firstangle, + last angle/.store in=\dbp@lastangle, + middle param/.store in=\dbp@midparam, + reverse/.is if=dubinspathreverse, +} + +\newcommand\dubinspathset[1]{\tikzset{dubins path,#1}} + +\newcommand\dubinspathcalc[1]{% + \begingroup + \dubinspathset{#1} + \tikzset{ + declare function={ + angtodist(\dbp@a,\dbp@r)={abs(\dbp@a)*.01745329*\dbp@r}; + modangr(\dbp@a,\dbp@b)={ + ( + Mod(\dbp@a,360)<Mod(\dbp@b,360) + ? + Mod(\dbp@a,360) + : + Mod(\dbp@a,360)-360)+\dbp@b-Mod(\dbp@b,360 + ) + }; + modangl(\dbp@a,\dbp@b)={ + ( + Mod(\dbp@a,360)<Mod(\dbp@b,360) + ? + Mod(\dbp@a,360)+360 + : + Mod(\dbp@a,360))+(\dbp@b)-Mod(\dbp@b,360) + }; + }, + } + + \pgfmathsetmacro\dbp@radius{\dbp@rradius} + \pgfmathsetmacro\dbp@anga{mod((\dbp@anga)+180,360)-180} + \pgfmathsetmacro\dbp@angb{mod((\dbp@angb)+180,360)-180} + \path + let + \p{a}=(\dbp@a), + \p{b}=(\dbp@b), + \p{ar}=($(\p{a}) + (\dbp@anga-90:\dbp@radius pt)$), + \p{al}=($(\p{a}) + (\dbp@anga+90:\dbp@radius pt)$), + \p{br}=($(\p{b}) + (\dbp@angb-90:\dbp@radius pt)$), + \p{bl}=($(\p{b}) + (\dbp@angb+90:\dbp@radius pt)$) + in \pgfextra{ + \pgfinterruptpath + + % RSR (ar and br) + \dbp@anglebetween\dbp@rsrarbr{\p{ar}}{\p{br}} + \dbp@distancebetween\dbp@rsrdarbr{\p{ar}}{\p{br}} + \pgfmathsetmacro\dbp@rsrangone{Mod(\dbp@anga-\dbp@rsrarbr,360)} + \pgfmathsetmacro\dbp@rsrangtwo{Mod(\dbp@rsrarbr-\dbp@angb,360)} + \pgfmathsetmacro\dbp@rsrlen{\dbp@rsrdarbr} + \pgfmathsetmacro\dbp@rsrdist{ + angtodist(\dbp@rsrangone,\dbp@radius) + +\dbp@rsrlen + +angtodist(\dbp@rsrangtwo,\dbp@radius) + } + \dbp@setparams{rsr}{\dbp@rsrdist}{\dbp@rsrangone}{\dbp@rsrlen}{\dbp@rsrangtwo} + + % LSL (al and bl) + \dbp@anglebetween\dbp@lslalbl{\p{al}}{\p{bl}} + \dbp@distancebetween\dbp@lsldalbl{\p{al}}{\p{bl}} + \pgfmathsetmacro{\dbp@lslangone}{mod(\dbp@lslalbl-\dbp@anga+720,360)} + \pgfmathsetmacro{\dbp@lslangtwo}{mod(\dbp@angb-\dbp@lslalbl+720,360)} + \pgfmathsetmacro\dbp@lsllen{\dbp@lsldalbl} + \pgfmathsetmacro\dbp@lsldist{ + angtodist(\dbp@lslangone,\dbp@radius) + +\dbp@lsllen + +angtodist(\dbp@lslangtwo,\dbp@radius) + } + \dbp@updateparams% + {lsl}{\dbp@lsldist}{\dbp@lslangone}{\dbp@lsllen}{\dbp@lslangtwo} + + % RSL (ar and bl) + \dbp@distancebetween\dbp@rsldarbl{\p{ar}}{\p{bl}} + \pgfmathtruncatemacro\dbp@rslok{(\dbp@rsldarbl>=2*\dbp@radius)?1:0} + \ifnumequal{\dbp@rslok}{1}{ + \dbp@anglebetween\dbp@rslarbl{\p{ar}}{\p{bl}} + \pgfmathsetmacro\dbp@rslanglesup{ + asin(\dbp@radius/\dbp@rsldarbl*2)} + \pgfmathsetmacro\dbp@rslangone + {Mod(\dbp@anga-\dbp@rslarbl+\dbp@rslanglesup,360)} + \pgfmathsetmacro\dbp@rslangtwo + {Mod(\dbp@angb-\dbp@rslarbl+\dbp@rslanglesup,360)} + \pgfmathsetmacro\dbp@rsllen{veclen(\dbp@rsldarbl,\dbp@radius)} + \pgfmathsetmacro\dbp@rsldist{ + angtodist(\dbp@rslangone,\dbp@radius) + +\dbp@rsllen + +angtodist(\dbp@rslangtwo,\dbp@radius) + } + + \dbp@updateparams% + {rsl}{\dbp@rsldist}{\dbp@rslangone}{\dbp@rsllen}{\dbp@rslangtwo} + }{} + + % LSR (al and br) + \dbp@distancebetween\dbp@lsrdalbr{\p{al}}{\p{br}} + \pgfmathtruncatemacro\dbp@lsrok{(\dbp@lsrdalbr>=2*\dbp@radius)?1:0} + \ifnumequal{\dbp@lsrok}{1}{ + \dbp@anglebetween\dbp@lsralbr{\p{al}}{\p{br}} + \pgfmathsetmacro\dbp@lsranglesup{ + asin(\dbp@radius/\dbp@lsrdalbr*2)} + \pgfmathsetmacro\dbp@lsrangone + {Mod(\dbp@lsralbr+\dbp@lsranglesup-\dbp@anga,360)} + \pgfmathsetmacro\dbp@lsrangtwo + {Mod(\dbp@lsralbr+\dbp@lsranglesup-\dbp@angb,360)} + \pgfmathsetmacro\dbp@lsrlen{veclen(\dbp@lsrdalbr,\dbp@radius)} + \pgfmathsetmacro\dbp@lsrdist{ + angtodist(\dbp@lsrangone,\dbp@radius) + +\dbp@lsrlen + +angtodist(\dbp@lsrangtwo,\dbp@radius) + } + \dbp@updateparams% + {lsr}{\dbp@lsrdist}{\dbp@lsrangone}{\dbp@lsrlen}{\dbp@lsrangtwo} + }{} + + % LRL (al and bl) + \dbp@distancebetween\dbp@lrldalbl{\p{al}}{\p{bl}} + \pgfmathtruncatemacro\dbp@lrlok{(\dbp@lrldalbl<=4*\dbp@radius)?1:0} + \ifnumequal{\dbp@lrlok}{1}{ + \dbp@anglebetween\dbp@lrlalbl{\p{al}}{\p{bl}} + \pgfmathsetmacro\dbp@lrlangsup{acos(\dbp@lrldalbl/\dbp@radius/4)} + \pgfmathsetmacro\dbp@lrlangone{ + modangl(\dbp@lrlalbl+\dbp@lrlangsup,\dbp@anga-90)-(\dbp@anga-90)} + \pgfmathsetmacro\dbp@lrlangtwo{% + (\dbp@angb-90)-modangr(\dbp@lrlalbl+180-\dbp@lrlangsup,\dbp@angb-90)} + \pgfmathsetmacro\dbp@lrlangthree{360-2*(90-\dbp@lrlangsup)} + \pgfmathsetmacro\dbp@lrldist{ + angtodist(\dbp@lrlangone,\dbp@radius) + +angtodist(\dbp@lrlangthree,\dbp@radius) + +angtodist(\dbp@lrlangtwo,\dbp@radius) + } + \dbp@updateparams% + {lrl}{\dbp@lrldist}{\dbp@lrlangone}{\dbp@lrlangthree}{\dbp@lrlangtwo} + }{} + + % RLR (ar and br) + \dbp@distancebetween\dbp@rlrdarbr{\p{ar}}{\p{br}} + \pgfmathtruncatemacro\dbp@rlrok{(\dbp@rlrdarbr<=4*\dbp@radius)?1:0} + \ifnumequal{\dbp@rlrok}{1}{ + \dbp@anglebetween\dbp@rlrarbr{\p{ar}}{\p{br}} + \pgfmathsetmacro\dbp@rlrangsup{acos(\dbp@rlrdarbr/\dbp@radius/4)} + \pgfmathsetmacro\dbp@rlrangone{ + (\dbp@anga+90)-modangr(\dbp@rlrarbr-\dbp@rlrangsup,\dbp@anga+90)} + \pgfmathsetmacro\dbp@rlrangtwo{% + modangl(\dbp@rlrarbr+180+\dbp@rlrangsup,\dbp@angb+90)-(\dbp@angb+90)} + \pgfmathsetmacro\dbp@rlrangthree{360-2*(90-\dbp@rlrangsup)} + \pgfmathsetmacro\dbp@rlrdist{ + angtodist(\dbp@rlrangone,\dbp@radius) + +angtodist(\dbp@rlrangthree,\dbp@radius) + +angtodist(\dbp@rlrangtwo,\dbp@radius) + } + \dbp@updateparams% + {rlr}{\dbp@rlrdist}{\dbp@rlrangone}{\dbp@rlrangthree}{\dbp@rlrangtwo} + }{} + + \endpgfinterruptpath + }; + \endgroup +} +% \end{macrocode} +% \iffalse +%</tikzlibrarydubins.code.tex> +% \fi +% +% \PrintChanges +% +% \setcounter{IndexColumns}{2} +% \PrintIndex +% +% \Finale +% +% \iffalse +%<*sankeydocpreamble> +\usepackage[paper=a4paper,vmargin=1.5cm,left=4.5cm,right=3.5cm]{geometry} +\usepackage[utf8]{inputenc} +\usepackage{cmap} +\usepackage[T1]{fontenc} +\usepackage{lmodern} +\usepackage[final,protrusion=true,expansion=true]{microtype} +\usepackage{xcolor} +\PassOptionsToPackage{final,colorlinks,linkcolor=red!60!orange!85!black}{hyperref} +\usepackage[numbered]{hypdoc} +\usepackage{fancyvrb} +\usepackage[final]{listings} +\usepackage{enumitem} +\usepackage{bookmark} +\usepackage{siunitx} +\usepackage{footnote} +\usepackage{etoc} +\usepackage{accsupp} +\usepackage{tikz} +\usetikzlibrary{positioning,patterns.meta,fit} +\usepackage[british]{babel} +\usepackage{varioref} +\usepackage{embedfile} +\usepackage{dtx-attach} +\embedfile[mimetype=text/plain]{sankey.ins} +\usepackage{sankey} + +\colorlet{bgcode}{yellow!50!gray!5} +\colorlet{keyword}{blue!50!cyan!50!black} +\colorlet{comment}{red!75!black} + +\newcommand\emptyaccsupp[1]{\BeginAccSupp{ActualText={}}#1\EndAccSupp{}} + +\lstset{ + literate= + {á}{{\'a}}1 {é}{{\'e}}1 {í}{{\'i}}1 {ó}{{\'o}}1 {ú}{{\'u}}1 + {Á}{{\'A}}1 {É}{{\'E}}1 {Í}{{\'I}}1 {Ó}{{\'O}}1 {Ú}{{\'U}}1 + {à}{{\`a}}1 {è}{{\`e}}1 {ì}{{\`i}}1 {ò}{{\`o}}1 {ù}{{\`u}}1 + {À}{{\`A}}1 {È}{{\'E}}1 {Ì}{{\`I}}1 {Ò}{{\`O}}1 {Ù}{{\`U}}1 + {ä}{{\"a}}1 {ë}{{\"e}}1 {ï}{{\"i}}1 {ö}{{\"o}}1 {ü}{{\"u}}1 + {Ä}{{\"A}}1 {Ë}{{\"E}}1 {Ï}{{\"I}}1 {Ö}{{\"O}}1 {Ü}{{\"U}}1 + {â}{{\^a}}1 {ê}{{\^e}}1 {î}{{\^i}}1 {ô}{{\^o}}1 {û}{{\^u}}1 + {Â}{{\^A}}1 {Ê}{{\^E}}1 {Î}{{\^I}}1 {Ô}{{\^O}}1 {Û}{{\^U}}1 + {œ}{{\oe}}1 {Œ}{{\OE}}1 {æ}{{\ae}}1 {Æ}{{\AE}}1 {ß}{{\ss}}1 + {ç}{{\c c}}1 {Ç}{{\c C}}1 {ø}{{\o}}1 {å}{{\r a}}1 {Å}{{\r A}}1 + {€}{{\texteuro}}1 {£}{{\pounds}}1 {°}{{\degres}}1 + {’}{{\textquoteright}}1 {‘}{{\textquoteleft}}1 + {«}{{<<}}1 {»}{{>>}}1 + {—}{{---}}1 {−}{{$-$}}1 + {\^\^A}{{}}0 % verbatim in .dtx file +} + +\lstset{ + fancyvrb=true, + escapechar=`, + extendedchars=true, + fontadjust=true, + columns=fullflexible, + flexiblecolumns=true, + inputencoding=utf8, + keepspaces=true, + backgroundcolor=\color{bgcode}, + basicstyle=\mdseries\ttfamily, + keywordstyle=\color{keyword}, + stringstyle=\ttfamily\color{green!50!black}, + commentstyle=\color{comment}\itshape, + emphstyle=\bfseries\color{red}, + numbersep=5pt, + %numbers=left, + numberstyle=\tiny\emptyaccsupp, + showstringspaces=false, + upquote=true, + aboveskip=.5\parskip, + belowskip=.5\parskip, + framexleftmargin=1pt, + framexrightmargin=1pt, + gobble=2, % \lstlisting code in .dtx +} + +\lstdefinestyle{textsmall}{basicstyle=\color{black}\small\mdseries\ttfamily} +\lstdefinestyle{textfootnotesize}{basicstyle=\color{black}\footnotesize\mdseries\ttfamily} +\lstdefinestyle{textscriptsize}{basicstyle=\color{black}\scriptsize\mdseries\ttfamily} +\lstdefinestyle{texttiny}{basicstyle=\color{black}\tiny\mdseries\ttfamily} + +\lstdefinestyle{LaTeX}{ + language=[LaTeX]TeX, + moretexcs={ + Lab, + LabSet, + Qty, + QtySet, + colorlet, + coordinate, + countries, + country, + countryname, + definecolor, + draw, + endcountry, + fill, + foreach, + hashband, + hdist, + hwidth, + node, + nodename, + path, + sankeyadvance, + sankeydubins, + sankeyend, + sankeyend, + sankeyfork, + sankeynode, + sankeynodealias, + sankeynodeend, + sankeynodestart, + sankeyoutin, + sankeyset, + sankeystart, + sankeyturn, + sankeyturnleft, + sankeyturnleftbackward, + sankeyturnright, + sankeyturnrightbackward, + sisetup, + startcountry, + tikzset, + turnandstop, + usepackage, + vdist, + } +} +\lstdefinestyle{LaTeXsmall}{style=LaTeX,style=textsmall} +\lstdefinestyle{LaTeXfootnotesize}{style=LaTeX,style=textfootnotesize} +\lstdefinestyle{LaTeXscriptsize}{style=LaTeX,style=textscriptsize} +\lstdefinestyle{LaTeXtiny}{style=LaTeX,style=texttiny} + +\def\code{\lstinline[basicstyle=\mdseries\ttfamily\color{red!50!black}]} + +\edef\samplecodename{\jobname-code.vrb} + +\newcommand\constant[1]{\textcolor{violet}{\texttt{#1}}} +\newcommand\ARG[1]{\texttt{\{#1\}}} +\newcommand\OPTARG[1]{\textcolor{green!50!black}{\texttt{[#1]}}} +\newcommand\VAR[1]{\textit{\texttt{\ensuremath{\langle}#1\ensuremath{\rangle}}}} +\newcommand\NOTE[1]{\leavevmode\marginpar{#1}} + +\def\mynobreakpar{\par\nobreak\@afterheading} +\def\docprefix#1{\texttt{\textcolor{gray}{#1}}} +\def\sankeykeysprefix{/sankey} + +\newenvironment{sankeyoption}[5][]{% [prefix] key, val, default, initially + \begingroup + % + \def\keypath{#1}% + \def\key{#2}% + \def\val{#3}% + \def\default{#4}% + \def\initially{#5}% + %\setlength\parindent{\dimexpr.5\parindent\relax}% + % \vspace{.25\baselineskip plus .25\baselineskip minus 0mm} + \parfillskip 0pt plus 1fil% + \leavevmode% + \ttfamily% + \hspace*{-1cm}% + \textcolor{red!75!black}{\texttt{\docprefix{\ifdefempty{\keypath}{\sankeykeysprefix/}{\keypath/}}\key}}% + \ifdefempty{\val}{}{=\val}% + \hfill% + \ifdefempty{\default}{\null}{(default:\,\constant{\default})}% + \ifdefempty{\initially}{\null}{(initially:\,\constant{\initially})}% + \mynobreakpar% + \endgroup% + \parskip=.5\baselineskip plus .25\baselineskip minus .25\baselineskip + \parfillskip=30pt plus 1fil + \itemize[topsep=0pt,partopsep=0pt,itemsep=0pt]\item[] +}{% + \enditemize% +} + +\newcommand\MACRO{\hspace*{-1cm}} + +\newlist{sankeyconstantsdesc}{description}{1} +\setlist[sankeyconstantsdesc]{align=right,labelindent=1.5em,labelsep=.5em,leftmargin=!,font=\normalfont} + +\newlength{\myparskip} +\setlength{\myparskip}{.75\baselineskip plus 8\baselineskip minus .25\baselineskip} +\usepackage[skip=\myparskip]{parskip} +\newenvironment{miniblock}{% + \vspace{.5\parskip}% +}{% +} + +\tikzset{ + every picture/.style={ + execute at end picture={ + \begin{pgfonlayer}{background} + \node[fit=(current bounding box),inner sep=0](bb){}; + \def\rs{5mm} + \draw[gray!25] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (\n{minx},\n{miny}) grid (\n{maxx},\n{maxy}); + \begin{scope}[overlay] + \draw[gray!50,-latex] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (\n{minx},0) -- (\n{maxx}+1mm,0); + \draw[gray!50,-latex] let + \p{sw}=(bb.south west), \p{ne}=(bb.north east), + \n{maxx}={ceil(\x{ne}/\rs)*\rs}, \n{minx}={floor(\x{sw}/\rs)*\rs}, + \n{maxy}={ceil(\y{ne}/\rs)*\rs}, \n{miny}={floor(\y{sw}/\rs)*\rs} + in (0,\n{miny}) -- (0,\n{maxy}+1mm); + \end{scope} + \end{pgfonlayer} + } + } +} + +\def\MacroFont{ + \fontencoding\encodingdefault + \fontfamily\ttdefault + \fontseries\mddefault + \fontshape\shapedefault + \footnotesize% +} +%</sankeydocpreamble> +% \fi +\endinput + +% Local Variables: +% mode: doctex +% LaTeX-verbatim-macros-with-braces-local: ("code") +% TeX-master: t +% End: diff --git a/Master/texmf-dist/source/latex/sankey/sankey.ins b/Master/texmf-dist/source/latex/sankey/sankey.ins new file mode 100644 index 00000000000..ab11ca1dc11 --- /dev/null +++ b/Master/texmf-dist/source/latex/sankey/sankey.ins @@ -0,0 +1,85 @@ +%% +%% 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 +%% + +\input docstrip.tex +\keepsilent + +\usedir{tex/latex/sankey} + +\preamble + +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 + +\endpreamble + +\generate{% + \askforoverwritefalse + \file{sankey.sty}{\from{sankey.dtx}{sankey}}% + \file{tikzlibrarydubins.code.tex}{\from{sankey.dtx}{tikzlibrarydubins.code.tex}}% + \file{sankey-example-energy.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example-energy}}% + \file{sankey-example1.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example1}}% + \file{sankey-example2.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example2}}% + \file{sankey-example3.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example3}}% + \file{sankey-example3-variation.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example3-variation}}% + \file{sankey-example4.tex}{\nopreamble\nopostamble\from{sankey.dtx}{example4}}% + \file{sankey-doc-preamble.sty}{\from{sankey.dtx}{sankeydocpreamble}}% +} + +\Msg{*********************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the} +\Msg{* following file into a directory searched by TeX:} +\Msg{*} +\Msg{* \space\space sankey.sty} +\Msg{* \space\space tikzlibrarydubins.code.tex} +\Msg{*} +\Msg{* To produce the documentation run the file sankey.dtx} +\Msg{* through (pdf)LaTeX.} +\Msg{*} +\Msg{* Happy TeXing!} +\Msg{*********************************************************} + +\endbatchfile
\ No newline at end of file |