% -*- coding: utf-8; -*- % Copyright (C) 2016-2021 by Paul Gaborit % % This file may be distributed and/or modified % % 1. under the LaTeX Project Public License and/or % % 2. under the GNU Public License. \documentclass[a4paper,onecolumn,10pt]{article} %\usepackage[rgb]{xcolor} \usepackage[paper=a4paper,vmargin=1.5cm,hmargin=4cm]{geometry} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} \usepackage{xcolor} \usepackage[colorlinks]{hyperref} \usepackage{fancyvrb} \usepackage{listings} \usepackage{enumitem} \usepackage{pgfilecontents} \usepackage{microtype} \usepackage{bookmark} \usepackage{cmap} \usepackage{sankey} \usepackage{siunitx} \usepackage{mdframed} \usepackage{footnote} \usepackage{accsupp} \usetikzlibrary{positioning,patterns.meta} \usepackage[british]{babel} \colorlet{fondcode}{gray!5!white} \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 } \lstset{ fancyvrb=true, %fvcmdparams=samepage, escapechar=`, % pour introduire du latex dans un environnement verbatim extendedchars=true, fontadjust=true, columns=fullflexible, % pour pouvoir copier/coller les chaines de caractères flexiblecolumns=true, % frame=leftline, inputencoding=utf8, keepspaces=true, % keeps spaces in text, code indentation backgroundcolor=\color{fondcode}, basicstyle=\mdseries\ttfamily, keywordstyle=\color{keyword}\bfseries,% 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, % pour pouvoir copier/coller le code avec des quotes aboveskip=\parskip, belowskip=\parskip, framexleftmargin=1pt, framexrightmargin=1pt, } \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, %backgroundcolor=\color{latexbg}, moretexcs={ coordinate, definecolor, draw, fill, foreach, hashband, node, sankeyadvance, sankeydubins, sankeyend, sankeyend, sankeyfork, sankeynode, sankeynodealias, sankeynodeend, sankeynodestart, sankeyoutin, sankeyset, sankeystart, sankeyturn, sisetup, tikzset, turnandstop, usepackage, } } \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{<#1>}}} \newcommand\NOTE[1]{\leavevmode\marginpar{#1}} \makeatletter \def\mynobreakpar{\par\nobreak\@afterheading} \makeatother \def\docprefix#1{\texttt{\textcolor{gray}{#1}}} \def\sankeykeysprefix{/sankey} \newenvironment{sankeyoption}[5][]{% [prefix] key, val, default, initially % \begingroup \bgroup% % \def\path{#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{\path}{\sankeykeysprefix/}{\path/}}\key}}% \ifdefempty{\val}{}{=\textit{\val}}% \hfill \ifdefempty{\default}{\null}{(default:\,\constant{\default})}% \ifdefempty{\initially}{\null}{(initially:\,\constant{\initially})}% \mynobreakpar\egroup% \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} %\setlength{\parskip}{\myparskip} \newenvironment{miniblock}{% \vspace{.5\parskip}% \csname minipage*\endcsname[t]{1.0\linewidth}% \setlength{\parskip}{\myparskip}% }{% \csname endminipage*\endcsname% } \makeatletter \title{How to use the \texttt{sankey} package\\ to build Sankey diagrams\footnote{This file described version v\sankey@version.}} \date{Released \sankey@date} \author{Paul Gaborit\footnote{\href{mailto:paul.gaborit@gmail.com}{\texttt{paul.gaborit@gmail.com}}}} \hypersetup{ pdftitle=How to use the sankey package to buid Sankey diagrams (v\sankey@version), pdfauthor=Paul Gaborit, } \makeatother \begin{document} \maketitle \begin{abstract} The \texttt{sankey} package provides macros and environments to build \emph{Sankey diagrams}% \footnote{\url{https://en.wikipedia.org/wiki/Sankey_diagram}} (or \emph{flow diagram} in which the width of the arrows is proportional to the flow rate). The idea cames out from \href{https://tex.stackexchange.com/q/40159/14500}{this question} on \href{https://tex.stackexchange.com/}{TeX.StackExchange}. % \end{abstract} { \setlength{\parskip}{0pt} \tableofcontents \listoffigures } % ------------------------------------------------------------ \section{Preamble} % ------------------------------------------------------------ To use the \code{sankey} package, insert the following line in your preamble: \begin{lstlisting}[style=LaTeXsmall] \usepackage{sankey} \end{lstlisting} % ------------------------------------------------------------ \section{The \texttt{sankeydiagram} environment} % ------------------------------------------------------------ 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} % ------------------------------------------------------------ \section{Sankey diagram options} % ------------------------------------------------------------ The \code{sankey} package uses \code{pgfkeys} to define options via \emph{key=value} pairs. 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} 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} % ------------------------------------------------------------ \subsection{Keys to choose the scale} % ------------------------------------------------------------ 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}/\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$). % ------------------------------------------------------------ \subsection{Keys to define drawing parameters} % ------------------------------------------------------------ \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} % ------------------------------------------------------------ \subsection{Keys to choose drawing styles} % ------------------------------------------------------------ \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} % ------------------------------------------------------------ \subsection{Keys to define new \emph{start} and \emph{end} styles} % ------------------------------------------------------------ \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 composed in a TikZ scope where the origin is the current Sankey node center (and its name is \code{\name}) and the coordinate system is rotated by its orientation. % ------------------------------------------------------------ \subsection{The \emph{debug} key} % ------------------------------------------------------------ \begin{sankeyoption}{debug}{\VAR{boolean}}{true}{false} To debug a sankey diagram. \end{sankeyoption} % ------------------------------------------------------------ \section{Sankey nodes and flows} % ------------------------------------------------------------ % ------------------------------------------------------------ \subsection{Create Sankey nodes} % ------------------------------------------------------------ % ------------------------------------------------------------ \begin{miniblock} \MACRO\code{\sankeynode}\OPTARG{\VAR{options}}\ARG{\VAR{node parameters}} 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}, an \emph{angle} and a \emph{position} 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}}{}{} 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}{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}. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[debug] \draw[gray!30] (-1,-1) grid (8,2); \sankeynode{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} % ------------------------------------------------------------ \begin{miniblock} \MACRO\code{\sankeynodestart}\OPTARG{\VAR{options}}\ARG{\VAR{node parameters}} The \code{\sankeynodestart} creates and fills/draws a starting Sankey node: \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodestart{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} % ------------------------------------------------------------ \begin{miniblock} \MACRO\code{\sankeynodeend}\OPTARG{\VAR{options}}\ARG{\VAR{node parameters}} The \code{\sankeynodeend} creates and fills/draws an ending Sankey node: \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[end style=simple,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodeend{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsection{Retrieve informations from a Sankey node} \MACRO\code{\sankeygetnodeqty}\ARG{\VAR{node name}} The expandable command \code{\sankeygetnodeqty} returns the quantity assigned to the Sankey node named \VAR{node name}. \MACRO\code{\sankeygetnodeorient}\ARG{\VAR{node name}} The expandable command \code{\sankeygetnodeorient} returns the angle (orientation) assigned to the Sankey node named \VAR{node name}. % ------------------------------------------------------------ \newpage \subsection{Move nodes} % ------------------------------------------------------------ The \code{\sankeyadvance} and \code{\sankeyturn} commands 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 (if you move the \code{a} node, its previous position is the \code{a-old} node). \subsubsection{forward commands} \begin{miniblock} \MACRO\code{\sankeyadvance}\OPTARG{\VAR{options}}\ARG{\VAR{node name}}\ARG{\VAR{distance}} The \code{\sankeyadvance} moves the sankey node straight ahead and fills/draws this portion of the sankey path. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodestart{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \begin{miniblock} \MACRO\code{\sankeyturn}\OPTARG{\VAR{options}}\ARG{\VAR{node name}}\ARG{\VAR{angle}} 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{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=arrow,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodestart{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsubsection{backward commands} \begin{miniblock} \MACRO\code{\sankeyadvance*}\OPTARG{\VAR{options}}\ARG{\VAR{node name}}\ARG{\VAR{distance}} The \code{\sankeyadvance*} moves the sankey node straight back and fills/draws this portion of the sankey path. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[end style=arrow,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodeend{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \begin{miniblock} \MACRO\code{\sankeyturn*}\OPTARG{\VAR{options}}\ARG{\VAR{node name}}\ARG{\VAR{angle}} The \code{\sankeyturn*} macro moves the sankey node backwards 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{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[end style=simple,fill/.style={fill=orange!20}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynodeend{name=a,quantity=10,angle=0,at={0,0}} \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={5,1},anchor=right} \sankeyturn*{c}{180} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsection{Links between nodes} \begin{miniblock} \MACRO\code{\sankeyoutin}\OPTARG{\VAR{options}}\ARG{\VAR{node A}}\ARG{\VAR{node B}} The \code{\sankeyoutin} macro fills/draws a lane between \VAR{node A} and \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} guaranted! \end{miniblock} \begin{miniblock} \MACRO\code{\sankeydubins}\OPTARG{\VAR{options}}\ARG{\VAR{node A}}\ARG{\VAR{node B}} 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 guaranted. \end{miniblock} \subsubsection{Comparison betwen \texttt{outin} and \texttt{dubins} paths} \begin{miniblock} \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=simple,end style=arrow] \draw[gray!30] (0,-1) grid (10,3.5); % \sankeyset{fill/.style={fill=orange!20}} \sankeynodestart{name=a,at={1,0},angle=0,quantity=5} \sankeynodeend{name=b,at={5,3},angle=0,quantity=5} \sankeyoutin{a}{b} % \sankeyset{fill/.style={fill=red!20}} \sankeynodestart{name=a,at={3,0},angle=0,quantity=5} \sankeynodeend{name=b,at={7,3},angle=0,quantity=5} \sankeyoutin[outin steps=2]{a}{b} % \sankeyset{fill/.style={fill=lime!40}} \sankeynodestart{name=a,at={5,0},angle=0,quantity=5} \sankeynodeend{name=b,at={(9,3},angle=0,quantity=5} \sankeydubins[minimum radius=5mm]{a}{b} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \begin{miniblock} \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=simple,end style=arrow] \draw[gray!30] (0,0) grid (8,4.5); % \sankeyset{fill/.style={fill=orange!20}} \sankeynodestart{name=a,at={1,1},angle=0,quantity=5} \sankeynodeend{name=b,at={3,4},angle=0,quantity=5} \sankeyoutin{a}{b} % \sankeyset{fill/.style={fill=red!20}} \sankeynodestart{name=a,at={3,1},angle=0,quantity=5} \sankeynodeend{name=b,at={5,4},angle=0,quantity=5} \sankeyoutin[outin steps=2]{a}{b} % \sankeyset{fill/.style={fill=lime!40}} \sankeynodestart{name=a,at={5,1},angle=0,quantity=5} \sankeynodeend{name=b,at={(7,4},angle=0,quantity=5} \sankeydubins[minimum radius=5mm]{a}{b} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \begin{miniblock} \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=simple,end style=arrow] \draw[gray!30] (0,0) grid ((6,4.5); % \sankeyset{fill/.style={fill=orange!20}} \sankeynodestart{name=a,at={1,1},angle=0,quantity=5} \sankeynodeend{name=b,at={1,4},angle=0,quantity=5} \sankeyoutin{a}{b} % \sankeyset{fill/.style={fill=red!20}} \sankeynodestart{name=a,at={3,1},angle=0,quantity=5} \sankeynodeend{name=b,at={3,4},angle=0,quantity=5} \sankeyoutin[outin steps=2]{a}{b} % \sankeyset{fill/.style={fill=lime!40}} \sankeynodestart{name=a,at={5,1},angle=0,quantity=5} \sankeynodeend{name=b,at={(5,4},angle=0,quantity=5} \sankeydubins[minimum radius=5mm]{a}{b} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsubsection{Examples of \texttt{dubins} paths} \begin{miniblock} \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[start style=simple,end style=arrow] \draw[gray!30] (-1,-1) grid (10,2.5); \sankeyset{ fill/.style={fill=lime!40}, draw/.style={draw=green!50!black,line width=2pt}, } \sankeynodestart{name=a,at={0,0},angle=0,quantity=5} \sankeynodeend{name=b,at={0,2},angle=0,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},angle=0,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},angle=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},angle=0,quantity=5} \sankeynodeend{name=b,at={7,1.75},angle=0,quantity=5} \sankeydubins[minimum radius=2.5mm]{a}{b} \sankeynodestart{name=a,at={9,0},angle=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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsection{Pure filling/drawing macros} \begin{miniblock} \MACRO\code{\sankeystart}\OPTARG{\VAR{options}}\ARG{\VAR{name}} The \code{\sankeystart} fills/draws a starting extremity attached to the preexistent Sankey node \VAR{name}: \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram} [start style=arrow,fill/.style={fill=cyan!20},draw/.style={draw=blue}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynode{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} % ------------------------------------------------------------ \begin{miniblock} \MACRO\code{\sankeyend}\OPTARG{\VAR{options}}\ARG{\VAR{name}} The \code{\sankeyend} fills/draws an ending extremity attached to the preexistent Sankey node \VAR{name}: \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram} [end style=simple,fill/.style={fill=cyan!20},draw/.style={draw=blue}] \draw[gray!30] (-1,-1) grid (8,2); \sankeynode{name=a,quantity=10,angle=0,at={0,0}} \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{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \subsection{Forked node} \begin{miniblock} \MACRO\code{\sankeyfork}\OPTARG{\VAR{options}}\ARG{\VAR{node}}\ARG{\VAR{quantity/name pairs}} The \code{\sankeyfork} macro splits a Sankey node in a list of new Sankey nodes. The \VAR{quantity/name pairs} is a comma separated list of \emph{quantity/name} pairs. The sum of all quantities \emph{must} be equal to the quantity of the node to fork. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram}[debug] \draw[gray!30] (-3,-2) grid (3,1); \sankeynode{name=a,quantity=50,angle=-80,at={0,0}} \sankeyfork{a}{30/b,10/c,10/d} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \begin{sankeydiagram} \sankeyset{ start style=arrow,end style=arrow, fill/.style={fill=yellow!10,line width=0pt,draw=yellow!10}, } \draw[gray!30] (-4,-3) grid (4,4); \sankeynode{name=a,quantity=40,angle=-90,at={0,0}} \sankeyfork{a}{25/b,10/c,5/d} \sankeyturn*{b}{90} \sankeyturn*[minimum radius=2cm]{c}{-45} \sankeyturn*[minimum radius=2cm]{c}{45} \sankeyturn*[minimum radius=5mm]{d}{-90} \sankeyadvance{a}{2cm} \foreach \nodename in {b,c,d}{ \sankeystart{\nodename} } \sankeyend{a} \end{sankeydiagram} \end{tikzpicture} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % {\centering\input{\samplecodename}\par} \end{miniblock} \section{Miscellaneous} \subsection{The \texttt{debug} layer} The \code{debug} option 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 informations: \begin{lstlisting}[style=LaTeXsmall] \sankeyset{ % debug color used by all debug macros debug color/.style={/utils/exec={\colorlet{debug color}{#1}}}, debug color=red!75!black, % debug line between left and right anchors debug line/.style={draw=debug color,|-|}, % debug line between center and label debug normal/.style={draw=debug color}, % debug node label debug label/.style={ draw, font=\ttfamily\tiny, text=debug color,text opacity=1, inner sep=.1em, fill=white,fill opacity=1, rounded corners=.1em, }, } \end{lstlisting} \subsection{The \texttt{dubins} TikZ library} 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. \subsection{How to duplicate a Sankey node} \MACRO\code{\sankeynodealias}\ARG{\VAR{origname}}\ARG{\VAR{clonename}} 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,angle=0,at={0,0}} \sankeynode{as=a,name=b} \end{lstlisting} \begin{lstlisting}[style=LaTeXsmall] \sankeynode{name=a,quantity=10,angle=0,at={0,0}} \sankeynodealias{a}{b} \end{lstlisting} \subsection{How to define new start and end styles} 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} \section{History} \begin{itemize} \item[v2.0] (2021/01/27) \begin{itemize} \item First public version (on CTAN). \end{itemize} \item[v1.0] (2016/03/06) \begin{itemize} \item First version. \end{itemize} \end{itemize} \clearpage \section{Examples} \subsection{Simple example} See figure~\ref{fig:simple-example}. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \colorlet{cold}[rgb]{cyan!75!blue!50!white} \colorlet{hot}[rgb]{red!50!orange!75!white} \begin{sankeydiagram} \sankeyset{ ratio=90pt/6, minimum radius=15pt, start style=simple, end style=simple, % debug, 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={0,100},angle=-90,quantity=6} \sankeyadvance{p0}{50pt} \sankeyfork{p0}{3/p1,3/p2} \sankeyturn{p1}{90} \sankeyadvance{p1}{20pt} \sankeyadvance{p2}{60pt} \sankeyfork{p2}{2/p3,1/p4} \sankeyturn{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} \sankeyturn{p4}{90} \sankeyadvance{p4}{65pt} \sankeyadvance{p7}{40pt} \sankeynode{name=p11,at={[shift={(50pt,-15pt)}]p7},angle=0,quantity=3} \sankeyfork{p11}{1/p7a,1/p9a,1/p5a} \sankeyoutin{p7}{p7a} \sankeyoutin{p9}{p9a} \sankeyoutin{p5}{p5a} \sankeyadvance{p11}{30pt} \sankeyend{p11} \sankeyturn{p8}{-90} \sankeyturn{p6}{-90} \sankeyturn{p4}{-90} \sankeyset{hot} \sankeyadvance[cold to hot]{p8}{40pt} \sankeynode{name=p10,at={[shift={(-15pt,-60pt)}]p8},angle=-90,quantity=3} \sankeyfork{p10}{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} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} \begin{figure}[b!] \centering \input{\samplecodename} \caption{Simple example} \label{fig:simple-example} \end{figure} \clearpage \subsection{Example from question on TeX.se} This example cames from \href{https://tex.stackexchange.com/q/40159/14500}{this question} on \href{https://tex.stackexchange.com/}{TeX.StackExchange}. See figure~\ref{fig:texse-example}. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} \renewcommand*\sfdefault{txss} \begin{sankeydiagram} \sankeyset{ ratio=4cm/524.3, minimum radius=3mm, start style=arrow, end style=arrow, % debug, fill/.style={ line width=0pt, fill=cyan!50!blue!50!black, draw=cyan!50!blue!50!black, }, draw/.style={draw=none}, } \sankeynodestart{name=B,at={-.5,0},angle=-90,quantity=7.2} \coordinate[below=1mm of B.center] (B label); \sankeyadvance{B}{5mm} \sankeynodestart{name=GI,at={1,0},angle=-90,quantity=137.3} \coordinate[below=1mm of GI.center] (GI label); \sankeyadvance{GI}{5mm} \sankeynodestart{name=I,at={4,0},angle=-90,quantity=397.8} \coordinate[below=1mm of I.center] (I label); \sankeynode{name=EI,at={2.86,-3},angle=-90,quantity=542.3} \sankeyfork{EI}{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} \sankeyturn{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} { \colorlet{NV color}{cyan!80!lime!50!gray} \sankeyset{fill/.append style={fill=NV color,draw=NV color}} \sankeyturn{NV}{90} \sankeynode{as=NV,name=NV2,at=NV -| EB} \sankeyoutin{NV}{NV2} \coordinate (NV label) at (NV -| EB label); \sankeyend{NV2} } \sankeyadvance{P}{10mm} \sankeyfork{P}{118.1/U,327.6/P} { \sankeyset{ fill/.style={fill=orange!70!gray!50,draw=orange!70!gray!50} } \sankeyturn{U}{90} \sankeynode{as=U,name=U2,at=U -| EB} \sankeyoutin{U}{U2} \coordinate (U label) at (U -| EB label); \sankeyend{U2} } \sankeyadvance{P}{10mm} \sankeyfork{P}{327.2/P,0.4/SD} { \sankeyturn{SD}{-90} \sankeyadvance{SD}{15mm} \coordinate (SD label) at (SD); \sankeyadvance{SD}{15mm} \sankeyend{SD} } \sankeyadvance{P}{8mm} \sankeyfork{P}{18.8/VE,308.4/E} { \sankeyset{fill/.append style={orange!70!gray!30}} \sankeyturn{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} \sankeyturn{In}{-90} \sankeyadvance{In}{10mm} \sankeyturn{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} \sankeyturn{H+GHD}{90} \sankeyadvance{H+GHD}{5mm} \sankeyfork{H+GHD}{47.0/GHD,88.1/H} \sankeyturn{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} \sankeyturn{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} \end{filecontents*} % \lstinputlisting[style=LaTeXsmall]{\samplecodename} % \begin{figure} \centering %\rule{\linewidth}{1pt}\\ \input{\samplecodename} \caption{Example from TeX.se question} \label{fig:texse-example} \end{figure} \clearpage \subsection{Very nice example -- Nadieh Bremer creation} 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~\ref{fig:nice-example}. \begin{filecontents*}{\samplecodename} \begin{tikzpicture} % \renewcommand*\sfdefault{txss} \sffamily \sisetup{ detect-all=true, group-separator={,}, group-minimum-digits=4, } % storage of labels \newcommand\LabSet[2]{% none name, label \expandafter\edef\csname #1Lab\endcsname{#2}} \newcommand\Lab[1]{% node name \csname #1Lab\endcsname} % storage of quantities \newcommand\QtySet[2]{% node name, quantity \expandafter\edef\csname #1Qty\endcsname{\fpeval{#2}}} \newcommand\Qty[1]{% node name \csname #1Qty\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 2 args={ overlay, align=flush center, node font=\footnotesize\sffamily\bfseries, inner sep=0, node contents={% {\mdseries€\,\num{#1}}\\% #2\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={\Qty{#1}}{\Lab{#1}},left label={1mm of #1-e.right}]; } \begin{sankeydiagram} \sankeyset{ ratio=28em/1000000, minimum radius=2cm, start style=none, % 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}}, % debug, } \coordinate (top) at (0,2em); \sankeynodestart{name=Pf,quantity=\Qty{Pf}, at={0,0},angle=-90} \node[cost node={\Qty{Pf}}{\Lab{Pf}},above=.5em of Pf.center]; \sankeynodestart{name=Sog,quantity=\Qty{Sog}, at={[xshift=4em]Pf.left},angle=-90,anchor=right} \node[cost node={\Qty{Sog}}{\Lab{Sog}},above=.5em of Sog.center]; \sankeynodestart{name=Sf,quantity=\Qty{Sf}, at={[xshift=2em]Sog.left},angle=-90,anchor=right} \node[cost node={\Qty{Sf}}{\Lab{Sf}},above=.5em of Sf.center]; \sankeynodestart{name=Os,quantity=\Qty{Os}, at={[xshift=2em]Sf.left},angle=-90,anchor=right} \node[cost node={\Qty{Os}}{\Lab{Os}},above=.5em of Os.center]; \sankeynode{name=R,quantity=\Qty{R}, at={[yshift=-10em]Sf.center},angle=-90} \sankeyfork{R}{\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={\Qty{R}}{\Lab{R}},right label hashed=R]; \sankeyfork{R}{\Qty{Ciffi}/Ciffi,\Qty{Nr}/Nr,\Qty{Coi}/Coi} \sankeyturn[minimum radius=1.cm]{Ciffi}{90} \node[cost node={\Qty{Ciffi}}{\Lab{Ciffi}}, at={([shift={(1mm,0)}]Ciffi.center)},rotate=-90, anchor=south,align=flush left,node font=\scriptsize\sffamily\bfseries]; \sankeyturn[green to greenwhite]{Coi}{-90} \sankeyadvance[greenwhite to white]{Coi}{1em} \node[cost node={\Qty{Coi}}{\Lab{Coi}}, left={1mm of [yshift=.75ex]Coi.left}, align=flush right,anchor=north east,overlay]; \sankeyadvance{Nr}{9em} \sankeyadvance{Nr}{1em} \node[cost node={\Qty{Nr}}{\Lab{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}, angle=-90,anchor=right,at={Nr2.right}} \sankeyfork{Ibiiieait}{\Qty{Oi}/Oi,\Qty{Nr2}/Nr2-e} \sankeyturn*[minimum radius=1cm,dashed]{Oi}{90} \node[cost node={\Qty{Oi}}{\Lab{Oi}},right label=1mm of Oi.left]; \sankeyadvance{Ibiiieait}{1em} \node[cost node={\Qty{Ibiiieait}}{\Lab{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}}, angle=-90,anchor=right,at={Ibiiieait2.right}} \sankeyfork{Ibit}{\Qty{Fi}/Fi,\Qty{Ibiiieait2}/Ibiiieait2-e} \sankeyturn*[minimum radius=1cm,dashed]{Fi}{90} \node[cost node={\Qty{Fi}}{\Lab{Fi}},right label=1mm of Fi.left]; \sankeyadvance{Ibit}{1em} \node[cost node={\Qty{Ibit}}{\Lab{Ibit}},right label hashed=Ibit]; \sankeyfork{Ibit}{\Qty{Niftp}/Niftp,\Qty{It}/It} \turnandstop{It} \sankeyadvance{Niftp}{6em} \sankeyadvance{Niftp}{1em} \node[cost node={\Qty{Niftp}}{\Lab{Niftp}},right label hashed=Niftp]; \sankeynode{name=Tci,quantity=\Qty{Niftp}+\Qty{Octa}, angle=-90,anchor=right,at={[yshift=-6em]Niftp.right}} \sankeyfork{Tci}{\Qty{Octa}/Octa,\Qty{Niftp}/Niftp-e} \sankeyoutin{Niftp}{Niftp-e} \sankeyturn*[minimum radius=1cm]{Octa}{90} \node[cost node={\Qty{Octa}}{\Lab{Octa}},right label=1mm of Octa.left]; \sankeyadvance{Tci}{1em} \node[cost node={\Qty{Tci}}{\Lab{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} \end{filecontents*} % \lstinputlisting[numbers=left,style=LaTeXsmall]{\samplecodename} % \begin{figure} \centering \input{\samplecodename} \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} \end{document} %%% Local Variables: %%% mode: latex %%% TeX-master: t %%% End: