---
title: "Decorating Sankey diagrams"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Decorating Sankey diagrams}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>",
  fig.ext = "png",
  dev = "png"
)
```

## Decorating nodes and edges with aesthetics

With the `waist` aesthetic you can modify the shape of the edge curve, this is
presented in more detail in the [Curve shape] section. Here it is shown how Nodes and edges can
be decorated with the `colour` (border of nodes and edges), `fill` (inside of nodes and edges),
and `alpha` aesthetics.

```{r aesthetics, fig.width=6.5, fig.height=4.5}
library(ggsankeyfier)
library(ggplot2)
theme_set(theme_light())
data("ecosystem_services")

## Let's subset the example data to create a less cluttered
## Sankey diagram
es_sub <-
  ecosystem_services |>
  subset(RCSES > 0.005) |>
  pivot_stages_longer(c("activity_realm", "biotic_realm", "service_section"),
                      "RCSES", "service_section")

ggplot(
  data    = es_sub,
  mapping = aes(x = stage, y = RCSES, group = node,
    edge_id = edge_id, connector = connector, colour = stage)) +
  ## apply fill and alpha aesthetic only to edges (not the nodes)
  geom_sankeyedge(aes(alpha = RCSES, fill = service_section)) +
  geom_sankeynode() +
  guides(fill   = guide_legend(ncol = 1),
         alpha  = guide_legend(ncol = 1),
         colour = guide_legend(ncol = 1)) +
  theme(legend.position = "top")
```

Note that both nodes and edges can be decorated separately. Also note that
each variable that is assigned to one or more aesthetics will get its
own guide legend. More about this in the section [Keys and legends].

## Additional layers

When you want to add additional layers to your plot (such as text labels), it is important
that those layers apply the same statistics and positioning as the `geom_sankeyedge` or
`geom_node` layers. To illustrate we first need a base plot onto which the layers can be added:

```{r deco_baseplot}
pos <- position_sankey(v_space = "auto", order = "ascending", align = "justify")

p <-
  ggplot(
  data    = es_sub,
  mapping = aes(x = stage, y = RCSES, group = node,
    edge_id = edge_id, connector = connector))
```

When you want to add additional layers and you want to let them line up with the nodes and
edges, all you need to do is: use a consistent call to `position_sankey()` for all layers;
and add the `stat_sankeyedge()` when you want to line up your layer with the edges in the
sankey diagram. This is shown in the example below where a `ggplot2::geom_segment()`
layer is added to the plot.

```{r layer_segment, fig.width=6, fig.height=3}
p +
  geom_sankeynode(position = pos) +
  geom_segment(aes(col = service_section),
               position = pos, stat = "sankeyedge",
               arrow = arrow(length = unit(0.2, "cm")))
```

When you want to align your layer with the nodes in a diagram, you need to add `stat_sankeynode()`
to your layer. Below a `ggplot2::geom_bar()` layer is added to the plot, which appears as a normal
`geom_sankeynode()` layer. This is because they are very similar but mostly just differ in the
positioning and stats that are applied.

```{r layer_bar, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(aes(fill = service_section), position = pos) +
  geom_bar(position = pos, stat = "sankeynode")
```

## Curve shape

The curves that connect the nodes in `ggsankeyfier` are drawn as symmetrical widened
[Bézier](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) curves. The slope of
the curve can be controlled with the `slope` parameter. The curve becomes very steep when
`slope = 1`:

```{r curve_shape, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(slope = 1, position = pos, mapping = aes(fill = service_section)) +
  geom_sankeynode(position = pos)
```

You could even go beyond the `slope` of 1, but then the curve will start to zigzag. With values
less than 1 will result in gentler slopes.

We can also play with how much the curve is widened. By default the width of the curve is
constant along the Bézier curve it follows. By setting the `waist` aesthetic, the width
of the curve is blown up, or shrunk down at its center. There are also `scale_waist_*` functions
(like `scale_waist_continuous()`), which allow you to adjust the appearance of the waist
and its legend keys.

```{r curve_waist, warning=FALSE, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(aes(waist = RCSES, fill = service_section), position = pos) +
  geom_sankeynode(position = pos)
```

## Keys and legends

Both nodes and edges have their own `draw_key()` function, meaning that they are
drawn automatically by `ggplot2::guide_legend()`. When multiple aesthetics
are based on the same variable, they are combined in a single legend (where possible).
In order to make this work, you will use the same guide (`"legend"` in case of the example
below) for both scales.

```{r legend_keys, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(aes(waist = RCSES, fill = RCSES), position = pos) +
  geom_sankeynode(position = pos) +
  scale_waist_binned(guide = "legend") +
  scale_fill_binned(guide = "legend")
```

## Different themes

At the top of this vignette we set `ggplot2::theme_light()` as the default theme.
It is also possible to add themes directly to the plot:

```{r theme_void, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(aes(fill = RCSES), position = pos) +
  geom_sankeynode(position = pos) +
  theme_void()
```

To change the colour scheme of the coloured aesthetics, you need to add the
appropriate colour scale. Let's add some turbo colours to our diagram:

```{r colour_turbo, fig.width=6, fig.height=3}
p +
  geom_sankeyedge(aes(fill = RCSES), position = pos) +
  geom_sankeynode(position = pos) +
  scale_fill_viridis_c(option = "turbo")
```
