This question led to a new package:
sankey
I would like to draw something similar to this (not exactly):
using TikZ. Ideally I would be able to set the width by variables and rejoin two flows into one again. Is there a good way to do this?
Since this will be my first TikZ diagram I am looking for pointers how to generally approach this problem, not for a complete solution, so that I can read the documentation effectively.
How would I branch of a (variable) portion of a rectangle? How would I rejoin such portions into one again?
partial solution:
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[scale=.5]
\draw[very thick] (1,0) -- (4,-1) -- (7,0) -- (7,-4) to [out=-90,in=180] (8,-5) -- (23,-5) -- (24,-6.5) -- (23,-8) -- (20,-8) to [out=180,in=0] (15,-10) -- (15,-10) (14,-10) -- (10,-10) to [out=0, in=90] (14,-14) -- (14,-8) to [out=90,in=0] (13,-7) -- (11,-7);
\draw[very thick] (15,-7) to [out=0,in=180] (20,-6) -- (11,-6) -- (13,-6) to [out=0,in=90] (15,-8) to (15,-20) -- (13.5,-21) -- (12,-20) to (12,-14) to [out=90,in=0] (11,-13) -- (5,-13) to [out=180,in=-90] (1,-9) to (1,0);
\draw[very thick] (4,-4) to [out=-90, in=180] (8,-8) -- (14,-8) (15,-8) -- (16,-8) to [out=0,in=180] (20,-7) to [out=180, in=0] (15,-9) (14,-9) -- (6,-9) to [out=180,in=-90] (4,-7) -- (4,-4);
\draw[very thick] (2,-6) to (2,-7) to [out=-90,in=180] (6,-11) -- (10,-11) to [out=0,in=90] (13,-14) -- (13,-14) to [out=90,in=0] (11,-12) -- (5,-12) to [out=180,in=-90] (2,-9) -- (2,-7);
\end{tikzpicture}
\end{document}
Gives:
but this is all hardcoded. I would ideally want to have the width of the flows variable (without needing to recalculate all the points by hand)
Syntax-wise I could imagine something like this:
\stream[width=x,direction=down] (initial_amount)
\redirect[initialamount,x\%][from=rightedge][to=right] (choide_A)
\redirect[choiceA,y\%][from=middle,rejoinrest=true][to=down] (choice_C)
\redirect[initial_amount,g\%][from=right][to=right] (choice_D) %i.e. that what's left of it after redirecting choice_A
\redirect[choid_D,h\%][from=left][to=down] (choice_E) %left in the sense that it the left side turned by 90 degrees
\join[initial_amount][choice_D][choice_C]
\join[choice_A][choice_E]
Points I'm thinking about
- streams have a flow direction, but tikz should be allowed to shift it (a right turn followed by a left turn or vice versa) for example when joining streams.
- layering should probably be so that first == lowest layer and whatever comes after should just pile on it
- straight portions, or shifting are adaptable in length/shift amount to whatever the spacing needs.
Update:
The following has a portion branching off to the right (\def'd by \choiceA)
\documentclass{article}
\usepackage{tikz}
\begin{document}
\def\startstreamx{1}
\def\startstreamy{1}
\def\initialwidth{6}
\def\initialheight{4}
\def\choiceA{.9}
\begin{tikzpicture}[scale=.5]
\draw[very thick] (\startstreamx,-\startstreamy-\initialheight) -- (\startstreamx,-\startstreamy) -- (\startstreamx+\initialwidth,-\startstreamy) -- (\startstreamx+\initialwidth,-\startstreamy-\initialheight);
\draw[very thick] (\startstreamx+\initialwidth,-\startstreamy-\initialheight) to [out=-90, in=180] (\startstreamx+\initialwidth+1,-\startstreamy-\initialheight-1);
\draw[very thick] (\startstreamx+\initialwidth-\choiceA*\initialwidth,-\startstreamy-\initialheight) to [out=-90, in=180] (\startstreamx+\initialwidth+1,-\startstreamy-\initialheight-1-\choiceA*\initialwidth);
\draw[very thick] (\startstreamx,-\startstreamy-\initialheight) to (\startstreamx,-\startstreamy-\initialheight-1-\choiceA*\initialwidth);
\draw[very thick] (\startstreamx+\initialwidth-\choiceA*\initialwidth,-\startstreamy-\initialheight) to (\startstreamx+\initialwidth-\choiceA*\initialwidth,-\startstreamy-\initialheight-1-\choiceA*\initialwidth);
\end{tikzpicture}
\end{document}
one could add now another such code snippet with the inital x and y and width values set to the end of the remaining (downwards) stream and again branch something off to the right.
Best Answer
Edit
Since release 3.0 of TikZ/PGF, the arguments of
atan2
are swapped.New Version (TikZ/PGF 3.0)
Here is a first attempt with my new environment
sankeydiagram
.Its optional argument is useful to fix some global parameters:
sankey tot quantity
is a number and represents the total quantity of the global flow (default value: 100 for 100%).sankey tot length
is the width of the global flow (default value: 100pt).sankey min radius
is the minimum radius of each turn (default value: 30pt).sankey fill
is the style used to fill the flows.sankey draw
is the style used to draw the flows.sankey debug
(a flag) is useful to debug a diagram during its construction (default value: false).The
sankeydiagram
environment defines some useful commands to construct a sankey diagram:\sankeynode{prop}{angle}{name}{pos}
makes a sankey node (a flow) of prop capacity (in quantity units), namedname
. Its orientation and position are given by angle and pos.\sankeynodestart
and\sankeynodeend
are similar to\sankeynode
(same arguments) but make respectively and flow starting and a flow ending.\sankeyadvance{name}{distance}
moves forward the sankey node named name.\sankeyturn{name}{angle}
turns the sankey node named name.\sankeyfork{name}{list of forks}
forks the sankey node named name. The list of forks is a list of pairs: quantity/name (the sum of quantities must be equal to the quantity of sankey node to fork).Here is the results (first without
sankey debug
then withsankey debug
).And, now, the code:
Here is another example with the same preamble (it's the same sankey diagram as your first example but with adjusted value: Industrie=86.1 . Without adjustment, there are bad sums...) :
Then the code (without preamble):