# ETL
library(tidyverse)
# Charts
library(networkD3)17 Sankey chart
In this section, we’re going to create a Sankey chart .
A Sankey chart is a flow diagram where the width of the connecting lines (links) is proportional to the quantity of the flow. It is used to visualize the movement of resources, energy, or data between different stages or categories (nodes).
In Supply Chain, it is a very useful way to display a flow of products.
Let’s start by uploading the libraries we will use : tidyverse for the ETL, and this time the new library networkD3 for the charts.
We will use a demo data frame to create our chart, downloaded from the URL below :
# upload dataset
# Define the URL of the raw CSV file
url <- "https://raw.githubusercontent.com/nguyennico/chart_practice/main/Distribution_Network_data.csv"
# Read the CSV file from the URL
initial_data <- read.csv(url)
glimpse(initial_data)Rows: 15
Columns: 5
$ distribution_center <chr> "Jakarta", "Jakarta", "Jakarta", "Jakarta", "Jakar…
$ channel_type <chr> "Wholesaler", "Wholesaler", "Wholesaler", "Wholesa…
$ customer_name <chr> "Distributor 1", "Distributor 1", "Distributor 1",…
$ product <chr> "Product A", "Product B", "Product C", "Product A"…
$ sales_qty <int> 1000, 2000, 800, 3200, 1700, 1000, 400, 900, 2000,…
It’s a data frame with 5 variables :
4 dimensions : distribution_center | channel_type | customer_name | product.
1 measure : sales_qty.
We will display the flow of products, from the Distribution Centers to the Customers (and the type of channel they are related to), based on the sales quantity.
A Sankey chart is created through 3 steps :
create links
sankey’s levels.
link (stack) the different levels.
create nodes : parent & child.
then finally : display of the chart.
18 Create Links
18.1 Create levels
Here is the concept :
we create blocks (i.e. levels) of 2 dimensions and 1 value.
each level follows each other, using one dimension of the previous level.
the previous dimension is called Parent.
the next dimension is called Child.
Each level has the same 3 variables :
2 dimensions : Parent & Child.
1 measure.
#---------------------------------------------------------
# Sankey Level 1: distribution_center & Products
# aggregate
df1 <- initial_data |>
group_by(distribution_center, channel_type) |>
summarise(sales_qty = sum(sales_qty)
)
# rename
df1 <- df1 |> rename(Parent = distribution_center,
Child = channel_type
)
# keep results
Links_distribution_center_to_channel_type_data <- df1
#---------------------------------------------------------
# Sankey Level 2: channel_type & customer_name
# aggregate
df1 <- initial_data |>
group_by(channel_type, customer_name) |>
summarise(sales_qty = sum(sales_qty)
)
# rename
df1 <- df1 |> rename(Parent = channel_type,
Child = customer_name
)
# keep results
Links_channel_type_to_customer_name_data <- df1
#---------------------------------------------------------
# Sankey Level 3: customer_name & product
# aggregate
df1 <- initial_data |>
group_by(customer_name, product) |>
summarise(sales_qty = sum(sales_qty)
)
# rename
df1 <- df1 |> rename(Parent = customer_name,
Child = product
)
# keep results
Links_customer_name_to_product_data <- df118.2 Link different levels
Now we are going to create the Links data frame :
stacking the different data frames which each level.
then sorting by decreasing value of the measure.
# stack data
Links <- rbind(Links_distribution_center_to_channel_type_data ,
Links_channel_type_to_customer_name_data,
Links_customer_name_to_product_data)
# sort by decreasing value
Links <- Links |> arrange(desc(sales_qty))
Links# A tibble: 23 × 3
# Groups: Parent [9]
Parent Child sales_qty
<chr> <chr> <int>
1 Jakarta Wholesaler 17500
2 Wholesaler Distributor 2 5900
3 Wholesaler Distributor 4 4500
4 Jakarta Direct 4100
5 Wholesaler Distributor 1 3800
6 Wholesaler Distributor 3 3300
7 Distributor 2 Product A 3200
8 Direct Convenience Store 2700
9 Distributor 4 Product B 2400
10 Distributor 1 Product B 2000
# ℹ 13 more rows
19 Create Nodes
And finally we create some nodes.
Nodes are unique combinations of Parents x Child from the Links data frame.
# create the Nodes dataframe based on the Links df
Nodes <- data.frame(name = unique(c(Links$Parent, Links$Child)))20 Display Sankey chart
Here we are!
Now we can display our sankey chart, using the function sankeyNetwork() .
This function uses as inputs the 2 data frames we previously created : Links and Nodes.
Before this, we also create 2 additional variables in the data frame Links : source and target.
It’s to indicate the relation between the Parent and Child of the Links data frame with the names in the Nodes data frame. We use the function
match().- The
match()function returns a vector of the positions (indices) of the first match of elements from the first argument (x) within the second argument
- The
those 2 new variables from the Links data frame are also 2 inputs of the function
sankeyNetwork().
# add the IDs to the Links df
Links$source <- match(Links$Parent, Nodes$name) - 1
Links$target <- match(Links$Child, Nodes$name) - 1
#---------------------------------------------------------
# (d3) Plot. Sankey Products
# chart Sankey
sankeyNetwork(
Links = Links,
Nodes = Nodes,
Source = "source",
Target = "target",
Value = "sales_qty",
NodeID = "name",
units = "units",
fontSize = 12,
nodeWidth = 30)Links is a tbl_df. Converting to a plain data frame.
Through this Sankey chart we can visualize the movement of the flows from the Distribution Center located in Jakarta :
mainly through a Wholesaler channel, with some relatively equal Distributors (4 in total).
some Products are more distributed by some wholesalers than others (for example, the Product C is mainly distributed by the Distributor 3).