1

I'd like to use the LaTeX Sankey package to draw the following closed-loop circular flow diagram, where the width or thickness of the arrows are indicative of the magnitude of the flow they represent.

The main challenge is how to create the closed-loops from the boxes labelled Green Plants, Animals , Decay and Fuel back toward the box labelled CO2 in atmosphere and dissolved in water as part of the overall closed-loop system.

enter image description here

The above diagram does not specify the quantities for each of the flows, but I will need to do so. Being able to label each of the flows, either within or beside each arrow is part of what I will need to do once I've determined the quantities for each flow.

An added plus would be if there exists a GUI application (online or desktop Mac) that could be used to create/generate the LaTeX code for the above Sankey diagram, including the closed-loop flows and all the necessary labels.

Another plus would be to specify the color of each of the Sankey arrows/flows, e.g. to distinguish the relative flow quantities of Decay material. For example, I'd like to specify different colors for the arrows from Green Plants as opposed to Animals that would extend through Decay toward CO2 in atmosphere and dissolved in water.

The data is not set in stone and varies over time, so I will need the flexibility to adjust each of the Sankey arrows to suit the data. There will likely be several/many more Sankey arrows in the final Sankey chart than what is indicated in the above image depending on the actual data availability.

This is a big ask ... it is part of a larger message under development that I have not observed anywhere else. LaTeX has been an amazing tool and I wonder just how far I can go with it.

P.S. I recognize that the smartdiagram package will create circular closed-loop diagrams, but NOT with the differing width arrows of the Sankey package.

Update: A mea culpa from a slow coder ... particularly to Paul Gaborit, author of the sankey package.

Since my last posting, I had taken a l-o-n-g second look at the Simple example provided in the Sankey package. I am not as quick as I used to be, (and absent any GUI application) it has taken me some time to learn the Sankey code and apply what I have learned.

As soon as I realized that Gaborit's Sankey package could provide what I was looking for, I was hoping to provide something of a less-than-anemic solution so that I could avoid being embarrassed about my progress. That said, the following is a code dump of what I had assembled so far (only to find Paul's code posted with an amazing graphic solution when I logged back in today):

\documentclass{article}
\usepackage{tikz}
\usepackage{sankey}
\begin{document}


\begin{tikzpicture}
\begin{sankeydiagram}[debug=true] %[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{ 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}, }, }

\sankeyset{cold}
\sankeynodestart{name=p0,at={100,0},angle=0,quantity=6}
\sankeyadvance{p0}{50pt}
\sankeyfork{p0}{3/p1,3/p2}
\sankeyturnleft{p1}{90}
\sankeyadvance{p1}{30pt}
\sankeyturnright{p2}{90}
\sankeyadvance{p2}{20pt}
\sankeyfork{p2}{2/p3,1/p4}
\sankeyadvance{p3}{30pt}
\sankeyturnright{p3}{90}
\sankeyadvance{p3}{185pt}
\sankeyfork{p3}{1/p5,1/p6}
\sankeyadvance{p5}{50pt}
\sankeyfork{p1}{1/p8,1/p7,1/p9}
\sankeyadvance{p7}{10pt}
\sankeyadvance{p9}{60pt}
\sankeyturnleft{p9}{90}
\sankeyadvance{p9}{230pt}
\sankeyturnright{p4}{90}
\sankeyadvance{p4}{200pt}
\sankeyadvance{p7}{20pt}
\sankeyturnleft{p7}{90}
\sankeyadvance{p7}{200pt}
\sankeynode{ name=p11,at={[shift={(-20pt,-120pt)}]p7},angle=0,quantity=3, forked={1/p7a,1/p9a,1/p5a}, }
\sankeyoutin{p7}{p7a}
\sankeyoutin{p9}{p9a}
\sankeyoutin{p5}{p5a}
\sankeyadvance{p11}{30pt}
\sankeyend{p11}
\sankeyturnleft{p8}{90}
\sankeyadvance{p6}{43pt}
\sankeyturnright{p6}{75}
\sankeyturnright{p4}{90}
\sankeyset{hot}
\sankeyadvance[cold to hot]{p8}{160pt}
\sankeynode{ name=p10,at={[shift={(-45pt,-140pt)}]p8},angle=0,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}
\sankeynode{ name=p12,at={[shift={(+50pt,-22.5pt)}]p11},angle=0,quantity=6, forked={3/p11a,3/p10a}, }
\sankeyoutin[cold to hot]{p10}{p10a}
\sankeyoutin[cold to hot]{p11}{p11a}
\sankeyadvance{p12}{80pt}
\sankeyend{p12}
\end{sankeydiagram}
\end{tikzpicture}

\end{document}

The above code provided me with the following Sankey diagram:

My progress to date on creating a Sankey diagram.

Please note that I did NOT adjust the flow colors, partly as a way to link the above image back to the Simple example provided in the Sankey package. I needed to take baby steps all around as I learned about how to work with Paul's amazing package.

Paul's code of a solution (that he provided 7 hours ago) to my original question is so far beyond what I could have accomplished in many, many days of coding.

Thank you Paul for what is an amazing graphic package. I will need a few days to read through your code solution to now apply the proper widths to each of the flows in the graphic you have provided.

9

1 Answer 1

6

Here is an example using the sankey package and arbitrary values !

\documentclass[tikz]{standalone}
\usepackage{sankey}
\newcommand{\sankeyarrow}[1]{\draw (#1.left) -- ($(#1)!.5!90:(#1.right)$) -- (#1.right);}
\begin{document}
\begin{tikzpicture}
  \begin{sankeydiagram}
    \sankeynode{name=CO2,quantity=40}
    \sankeyfork{CO2}{10/RMGP-e,10/C-e,10/RMA-e,10/D-e}
    \sankeyadvance{CO2}{4cm}
    \fill[gray](CO2-old.left) rectangle (CO2.right);
    \node[align=flush center,text width=3cm] at ($(CO2-old)!.5!(CO2)$) {CO2 in atmosphere and dissolved in water};
    \sankeyadvance{CO2}{4cm}
    \node[align=flush center,text width=3cm] at ($(CO2-old)!.5!(CO2)$) {Photosynthesis};
    \sankeyadvance{CO2}{2cm}
    \sankeyarrow{CO2-old}
    \sankeyadvance{CO2}{4cm}
    \fill[fill=lime!80!black](CO2-old.left) rectangle (CO2.right);
    \node[align=flush center,text width=3cm] at ($(CO2-old)!.5!(CO2)$) {Green Plants};
    \sankeyfork{CO2}{10/RMGP,10/Fuel,15/Animals,5/DeathGP}
    \sankeyturnleft{RMGP}{180}
    \sankeyadvance{RMGP}{4cm}
    \node[align=flush center,text width=3cm] at ($(RMGP-old)!.5!(RMGP)$) {Respiration \& Metabolism};
    \sankeydubins{RMGP}{RMGP-e}
    \sankeyarrow{RMGP}
    \sankeyadvance{Fuel}{1.5cm}
    \sankeyturnleft{Fuel}{90}
    \sankeyadvance{Fuel}{3cm}
    \sankeyturnleft{Fuel}{90}
    \sankeyadvance{Fuel}{4cm}
    \fill[fill=orange](Fuel-old.left) rectangle (Fuel.right);
    \node[align=flush center,text width=3cm] at ($(Fuel-old)!.5!(Fuel)$) {Fuel};
    \sankeyadvance{Fuel}{4cm}
    \node[align=flush center,text width=3cm] at ($(Fuel-old)!.5!(Fuel)$) {Combustion};
    \sankeyadvance{C-e}{-1.5cm}
    \sankeyarrow{C-e}
    \sankeyturnleft{C-e}{-90}
    \sankeyadvance{C-e}{-3cm}
    \sankeyturnleft{C-e}{-90}
    \sankeydubins{Fuel}{C-e}
    \sankeyarrow{Fuel}
    \sankeyadvance{Animals}{1.5cm}
    \sankeyturnright{Animals}{90}
    \sankeyadvance{Animals}{3cm}
    \sankeyturnright{Animals}{90}
    \sankeyadvance{Animals}{4cm}
    \fill[pink](Animals-old.left) rectangle (Animals.right);
    \node[align=flush center,text width=3cm] at ($(Animals-old)!.5!(Animals)$) {Animals};
    \sankeyfork{Animals}{10/RMA,5/DeathA}
    \sankeyturnright{DeathA}{90}
    \sankeyturnleft{DeathA}{90}
    \sankeynode{
      name=Death,quantity=10,angle=180,
      forked={5/DeathA-e,5/DeathGP-e},
      fork anchor=DeathA-e.center,
      at=DeathA.center,
    }
    \sankeyturnright{DeathGP}{90}
    \sankeydubins{DeathGP}{DeathGP-e}
    \sankeyadvance{Death}{3cm}
    \node[align=flush center,text width=3cm] at ($(Death-old)!.5!(Death)$) {Death};
    \sankeyadvance{Death}{5mm}
    \sankeyarrow{Death-old}
    \sankeyadvance{Death}{4cm}
    \fill[cyan!50!blue!50](Death-old.left) rectangle (Death.right);
    \node[align=flush center,text width=3cm] at ($(Death-old)!.5!(Death)$) {Decay};
    \sankeydubins{Death}{D-e}
    \sankeyadvance*{RMA-e}{1.5cm}
    \sankeyarrow{RMA-e}
    \sankeyturnright*{RMA-e}{90}
    \sankeyadvance*{RMA-e}{4cm}
    \sankeyadvance{RMA}{4cm}
    \node[align=flush center,text width=3cm] at ($(RMA-old)!.5!(RMA)$) {Respiration \& Metabolism};
    \sankeydubins{RMA}{RMA-e}
    \sankeyarrow{RMA}
  \end{sankeydiagram}
\end{tikzpicture}
\end{document}

enter image description here

1
  • 1
    For beginners, the Sankey 'debug' feature is an ABSOLUTE necessity to get anywhere when constructing a Sankey diagram. It is simple enough to toggle on or off, so I leave debug ON ([debug=true]) while coding right up to the last second before a final compiling. Commented Jun 20, 2022 at 22:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .