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.

RosesBouquet
  • 569
  • 3
  • 13
  • Related: https://tex.stackexchange.com/questions/40159/how-to-draw-a-sankey-diagram-using-tikz (you can start trying something small, like a two-blocks with a feedback, and ask when you got stuck with a minimal example... – Rmano Jun 15 '22 at 07:31
  • @Rmano - Thanks for the suggestion ... at the moment I am looking into the Sankey Diagram Generator at https://csaladenes.wordpress.com/2014/11/06/sankey-diagram-generator/ that allows for feedback loops ... only issue (as best I can tell) is the code generated is JavaScript, which introduces another layer of complexity. – RosesBouquet Jun 15 '22 at 21:45
  • The Sankey Diagram Generator (https://csaladenes.wordpress.com/2014/11/06/sankey-diagram-generator/) is also available on GitHub at https://github.com/csaladenes/sankey. Aside from JavaScript, it appears the Generator also produces HTML code. Enjoy! – RosesBouquet Jun 15 '22 at 21:58
  • Per at least one website (https://www.sankey-diagrams.com/loopbacks-in-sankey-diagrams/) loopbacks in Sankey diagrams are not very common and can lead to "All sorts of routing issues for the arrow come up and you need to create room to not produce overlaps." The vast majority of Sankey diagrams "take a left-to-right column oriented approach when setting up the diagram". Loopbacks appear to be on the bleeding edge for Sankey displays. Many diagrams having circular links (https://www.sankey-diagrams.com/sankeys-with-circular-links/) are created using d3.js (https://observablehq.com/@d3/gallery) – RosesBouquet Jun 16 '22 at 07:42
  • After some research and reviewing the Sankey documentation it would appear that the Sankey package is not ready for the prime time that loopbacks represent. Under some time pressure, I am presently exploring block diagrams (https://tex.stackexchange.com/questions/268878/block-diagram-with-tikz) and closed loop diagrams (https://tex.stackexchange.com/questions/318762/drawing-a-closed-loop-diagram-with-tikz-with-multiple-inputs?rq=1) as a way to display the above flow diagram, just without the capability to size the arrows that I was attempting. Oh well ... it was worth a try ... – RosesBouquet Jun 16 '22 at 21:45
  • The sankey package can make this kind of diagrams. Can you provide the values to represent? – Paul Gaborit Jun 20 '22 at 12:03
  • @Paul Gaborit - I am in the process of collecting the values for the corresponding flows in the diagram from the latest IPCC reports, et al. Thank you for the amazing graphic! – RosesBouquet Jun 20 '22 at 22:49
  • @RosesBouquet With real values (and presumably other entry/exit arrows), this graphic could serve as a cyclical example in the documentation of the sankey package. – Paul Gaborit Jun 21 '22 at 04:43
  • @Paul Gaborit - Thank you for the thought ... I would very much like to have the graphic as part of the documentation of the Sankey package. I am currently attempting to garner the data that will populate the chart ... so as to ensure what I am presenting makes sense and is backed by the science. Apologies if it will take me a bit of time to jump from the IPCC report data to an actual chart. I'm new at this, but I believe a Sankey chart could be a powerful way to display the data. Thank you again for the thought. – RosesBouquet Jun 21 '22 at 05:05

1 Answers1

4

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

Paul Gaborit
  • 70,770
  • 10
  • 176
  • 283
  • 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. – RosesBouquet Jun 20 '22 at 22:45