Direkt zum Hauptbereich

die GuV als Sankey-Diagramm

 

Sankey (oder auch die ähnlichen Alluvial) Diagramme sind eigentlich nicht für Finanzstatements da. Doch habe ich im Internet schon einige Kombinationen gesehen, bei welchen die GUV als Sankey-Diagramm dargestellt wird. Es gibt sogar schon Anbieter hierfür; aber leider habe ich kein Tutorial und kaum Code-Beispiele gefunden. Im Folgenden versuche ich also das alles zu beheben und versuche das Q3 Ergebnis von Daimler Trucks als Sankey-Diagramm zu visualisieren.

die Daten

Zuerst müssen die Daten wiefolgt aufbereitet werden. Leider nicht ganz straight-forward, aber doch nachvollziehbar:

library(ggplot2)
library(ggsankey)
library(tidyverse)

data_q3 <- tribble(
  ~In, ~Mid, ~Mid2, ~Out, ~Value,
  "Revenue", "Cost of Sales", NA, NA, 10.886,
  "Revenue", "Gross Profit", NA, NA, 2.973,
  NA, "Gross Profit", "EBIT", NA, 1.219,
  NA, "Gross Profit", "Expenses", NA, 1.754,
  NA, "Cost of Sales", "Out", NA, 10.886,
  NA, NA, "EBIT", "Net Profit", 1.246,
  NA, NA, "EBIT", "Interests", 0.03,
  NA, NA, "EBIT", "Taxes", 0.03,
  NA, NA, "Expenses", "Selling", 0.729,
  NA, NA, "Expenses", "Administr.", 0.658,
  NA, NA, "Expenses", "R&D", 0.439)

head(data_q3)
## # A tibble: 6 × 5
##   In      Mid           Mid2     Out        Value
##   <chr>   <chr>         <chr>    <chr>      <dbl>
## 1 Revenue Cost of Sales <NA>     <NA>       10.9 
## 2 Revenue Gross Profit  <NA>     <NA>        2.97
## 3 <NA>    Gross Profit  EBIT     <NA>        1.22
## 4 <NA>    Gross Profit  Expenses <NA>        1.75
## 5 <NA>    Cost of Sales Out      <NA>       10.9 
## 6 <NA>    <NA>          EBIT     Net Profit  1.25

Date Crunching

Doch für den Plot muss die folgende Neuformatierung durchgeführt werden:

data_long = data_q3 %>% 
  make_long(In, Mid, Mid2, Out, value = Value) %>% 
  mutate(exclude = case_when(   #exclude = new column
    is.na(node) ~ "X",
    x == "Mid" & is.na(next_node) ~ "X",   # exclude the mid values without a next_node attribute
    x == "Mid2" & is.na(next_node) ~ "X",   # exclude the mid2 values without a next_node attribute
  )) %>% 
  filter(is.na(exclude)) %>%
  select(-exclude) %>%
  group_by(x, node) %>% 
  mutate(total = sum(value))
data_long$node <- factor(data_long$node,levels = c("Selling", "Administr.", "R&D", "Taxes", "Interests", "Net Profit", "Out", "Expenses", "EBIT","Cost of Sales", "Gross Profit", "Revenue"))
data_long$next_node <- factor(data_long$next_node,levels = c("Selling", "Administr.", "R&D", "Taxes", "Interests", "Net Profit", "Out", "Expenses", "EBIT","Cost of Sales", "Gross Profit", "Revenue"))
head(data_long)
## # A tibble: 6 × 6
## # Groups:   x, node [4]
##   x     node          next_x next_node     value total
##   <fct> <fct>         <fct>  <fct>         <dbl> <dbl>
## 1 In    Revenue       Mid    Cost of Sales 10.9  13.9 
## 2 In    Revenue       Mid    Gross Profit   2.97 13.9 
## 3 Mid   Gross Profit  Mid2   EBIT           1.22  2.97
## 4 Mid   Gross Profit  Mid2   Expenses       1.75  2.97
## 5 Mid   Cost of Sales Mid2   Out           10.9  10.9 
## 6 Mid2  EBIT          Out    Net Profit     1.25  1.31

Die Visualisierung

Und nun der folgende Code zur Visualisierung:

data_long %>% 
  ggplot(aes(x = x,
             next_x = next_x,
             node = node,
             next_node = next_node,
             fill = factor(node),
             value = value,
             label = paste0(node, "\n (", round(total,1), ")")
  ))   +
  geom_sankey(flow.alpha = 0.75, node.color = 1) +
  geom_sankey_label(size = 3.5, color = 1, fill = "white") +
  scale_fill_viridis_d(option = "A", alpha = 0.95) +
  theme_sankey(base_size = 16) +
  theme_void(base_size = 18) +
  theme(legend.position = "none")