*! version 1 April 7 2022

Title

sankey_plot -- Module to produce Sankey Plots

Syntax

sankey_plot
x0 y0 x1 y1
[if] [in]
[, sankey_options twoway_options]

Main: Sankey coordinates options

x0 y0 x1 y1 Required. This provides the coordinates and groups to
be plotted. (x0,y0) identifies the origin, and (x1,y1) the destination.
This values identify the nodes.

x0 and x1 must be numerical. They identify the horizonal levels of the connections. However y0 and y1 can be numerical or strings, but not both. If they are strings, those values will be used as labels. They identity nodes within levels.

width0(varname) Provides a variable with the weight or width at the origin (x0,y0). Default is 0.01

width1(varname) Provides a variable with the weight or width at the destinatin (x1,y1).
Default is the value in width0

Main: Sankey Look options

sharp(#) Uses # to define change the look of the conecting segments or links.
Default is 7. Must be larger than 0. A value of 1 produces a line.

adjust Adjust Ys coordinates to avoid overlapping within nodes.
However, the figure will remain "around" the original value of Y

extra Adjust Y coordinates based on width0 and/or width1. With this option
there will be no overlapping across nodes. Can be combined with adjust

gap(#) To be used in combination with extra. Request
to add a "gap" across nodes from the same level when using extra

noline Request connecting segments or links to be drawn without the border line

nobar Requests the Bars that connects segments/links not to be drawn.

Main: Sankey bar & label options options

bwidth(#) If the connecting Bar is kept, this can be used to modify
the width of that bar. Default 0.025.

bheight(#) When used, this modifies the height of all
connecting bars. Default is to use the hight of the connecting links

bcolor(colorstyle) When used, one can modify the color of the bar.
Default is to use the color of the following segment. This option superseeds other color options, but can be combined with pstyle

label0(varname) Provides a variable with the labels for the
origin coordinates. Must be String. Default None. Not needed if y0 and y1 are strings.

label1(varname) Provides a variable with the label for the
destination coordinates. Must be String. Default label0 if any. Not needed if y0 and y1 are strings

labangle(#) When label0 are provided,
one can use this option to modify the angle of labels. Default 0

labpos(#) When label0 are provided,
one can use this option to modify the possition of labels.
Default is to possition the label to the right of the first level,
and left of the last one.

labsize(#) When label0 are provided,
one can use this option to modify the size of the text for labels.

labcolor(colorstyle) When label0 are provided, or y0 y1 were strings, one can use this option to modify the color of the text for labels.

Main: Sankey color/style options

This command provides various options to add colors to all links and conecting bars.
The default is to use the current Scheme colors, which allows up to 15 different groups.

pstyle(varname) One can provide a variable that preassigns styles to a particular segment. One can choose from p1-p15. This can be combined with bcolor and fillcolor options.

color(varname) One can provide a variable that preassigns colors to a particular link. This cannot be combined with bcolor and fillcolor options. If those options are used, they will superseed color

fillcolor(color) One can use this option to define a single color for all connecting links. Using this option superseeds color and colorpalette options

colorpalette(options)
This option allows you to use color palettes using Ben Jann's colorpalette. Most options are allowed. However, the option opacity() will only affect the connecting links, not the connecting bars.

Main: Experimental

wide This is an experimental option. You can use it, for example, when each variable in your data
corresponds to a different horizontal level. See "dogs and happiness" example.

width(varname) If wide option is used, the weight of each flow should be defined with this option

tight If wide option is used, this option "compresses" categories to avoid multiple flows from and to same
nodes

Most other Sankey options are allowed. However, not all have been tested.

Main: twoway graph options

Most twoway_options are allowed, including name, title, subtitle, xlabel, etc. However, not all have been tested.

Description

sankey_plot is a module that aims to facilitate the creation of sankey plots in Stata. This command, however, does not make any data processing, and assumes the data is ready to be used.

At its core, a Sankey plot is nothing less than pairs of connected coordinates: from (x0,y0) -> (x1,y1). These points are connected with flows that have widths proportional to width0 and width1.

x0 and x1 identify the vertical levels of a plot. These variables must be numeric.

y0 and y1 identify different groups within levels. These variables can be numeric of string but not both. When string variables are used, those values are used as labels for the different groups within levels.

There are two main options to adjust coordinates:

adjust, which adjusts coordinates so that there is no overlapping of flows within groups.

extra, which adjusts coordinates based on width0 and width1, so that there is no overlapping across groups.

The command also allows you to use the command colorpalette to choose from different color palettes. Only available if correctly installed.

Examples

Immigration flows: The following contains data on immigration flows across continents.
It has data on 2 levels. Source and destination.

use immigration, clear

Simplest Sankey plot. Only connects observations across groups. Weights are default.

sankey_plot x0 from x1 to

Uses ticker widths. But flows overlap

gen w0 = 0.1

sankey_plot x0 from x1 to, width0(w0)

Uses ticker widths. But flows do not overlap

sankey_plot x0 from x1 to, width0(w0) adjust

Uses imigration flows as widths. This figure will be unreadable because all flows will overlap, even if using adjust

sankey_plot x0 from x1 to, width0(value)

sankey_plot x0 from x1 to, width0(value) adjust

This is a better figure, because it adjusts coordinates to widths

sankey_plot x0 from x1 to, width0(value) extra

Even better, because it also adjust overlapping

sankey_plot x0 from x1 to, width0(value) extra adjust

Now say you want to modify colors. You can change the colors of the flows using fillcolor.
you could change all to grey (gs12) or modify transparency, or both.

sankey_plot x0 from x1 to, width0(value) extra adjust fillcolor(gs12)

sankey_plot x0 from x1 to, width0(value) extra adjust fillcolor(%50)

You could also increase the gap across nodes

sankey_plot x0 from x1 to, width0(value) extra adjust fillcolor(%50) gap(0.1)

If you do not like the default colors of your scheme, you could use colorpalette. Notice that Im using opacity
and noline, to get cleaner flows

sankey_plot x0 from x1 to, width0(value) extra adjust colorpalette(viridis, opacity(40)) gap(0.1) noline

But what about the xlabels. The default is to use the values for x0 and x1. However, they can be changed

sankey_plot x0 from x1 to, width0(value) extra adjust colorpalette(viridis, opacity(40)) gap(0.1) noline xlabel(1 "Source" 2 "Destination", nogrid)

And of course, you can titles, name the graph, add notes

sankey_plot x0 from x1 to, width0(value) extra adjust colorpalette(HSV intense, opacity(40)) gap(0.1) noline xlabel(1 "Source" 2 "Destination", nogrid) title("Migration flows") note("Note:Abel, Guy J (2017) Estimates of Global Bilateral Migration Flows by Gender between 1960 and 2015")

JobMarket: The following contains data on Job market flows across many weeks. It has data on multiple levels.

In contrast with the previous plot, I will use labels explicilty

use jobmarket, clear

Lets Start with the simplest plot

sankey_plot week0 y0 week1 y1

Since I would like to keep the same shape as above, but using the provided widths, I will readjust the Y0 and Y1 coordinates

gen y00=y0*10

gen y11=y1*10

sankey_plot week0 y00 week1 y11, width0(candiates) adjust

Next I'll modify the colors, add labels and change the xlabels

sankey_plot week0 y00 week1 y11, width0(candidates) adjust xlabel(0 " " 1 "Week 1" 2 "Week 2" 3 "Week 3" 4 "Week 4" 5 "Week 5" 6 "Week 6", nogrid) fillcolor(gs12%50) label0(label0) label1(label1) xsize(10) ysize(6)

Same as above but using "extra" to adjust possition of nodes

sankey_plot week0 y00 week1 y11, width0(candidates) adjust extra xlabel(0 " " 1 "Week 1" 2 "Week 2" 3 "Week 3" 4 "Week 4" 5 "Week 5" 6 "Week 6", nogrid) fillcolor(gs12%50) label0(label0) label1(label1) xsize(10) ysize(6)

Pets, Marriage and Happiness: The following contains with a different structure. Rather than having pair of coordinates, we use
variables which identify the flows across nodes. This requires a slighly different syntax.

use dogs_and_happiness, clear

list

First the simplest Sankey requires to indicate you are going to use "wide" data

It is required to provide the width variable as well.

sankey_plot married pet happy , wide width(freq)

As before, lets change colors, add space within nodes, and drop the xlabels

sankey_plot married pet happy , wide width(freq) fillcolor(%50) xlabel("",nogrid) gap(0.1)

You will notice 2 groups in Married with pets who are happy. That can be fixed using "tight"

sankey_plot married pet happy , wide width(freq) fillcolor(%50) xlabel("",nogrid) gap(0.1) tight title("The Secret to Happyness") subtitle("Have Pets: Nora and Bruce!") note("Nora and Bruce belong to my wife and I")

Aknowledgement

This command came to life as part of a small programming challenge by Asjad, who created a step-by-step post of how to make Sankey Plots.
However, the structure of how this program works is different from his approach.

Questions comments and suggestions welcome.

Author

Fernando Rios-Avila

Levy Economics Institute of Bard College

Blithewood-Bard College

Annandale-on-Hudson, NY

friosavi@levy.org