0

Once again, I need your help and I'm looking forward to listen & learn.

I would like to depict the interrelation between several types of birds (t1 - t7). It is observed how frequently they interact with their own type or other types of birds (o1 - o7)

The data (bird.data) looks as follows:

type o1 o2 o3 o4 o5 o6 o7
t1 77.6 3.5 1.5 9.1 3.3 1.4 3.6
t2 10 64.4 9 3.2 2.1 7.4 3.9
t3 8.6 12.1 63.2 2.4 0.6 8.8 4.3
t4 28.7 5.1 2.0 51.4 5.8 0.3 6.6
t5 4.1 12.2 9.5 1.0 0.4 64.5 8.3
t6 10.9 3.6 0.3 6.5 66.8 2.0 9.9
t7 15.9 8.2 4.5 5.6 9.4 5.4 51.0
bird.data <- structure(list(type = c("t1”, “t2", “t3”, “t4”, “t5”, “t6”, “t7”), o1 = c(77.6, 10, 8.6, 28.7, 4.1, 10.9, 15.9), o2 = c(3.5, 64.4, 12.1, 5.1, 12.2, 3.6, 8.2), o3 = c(1.5, 9, 63.2, 2, 9.5, 0.3, 4.5), o4 = c(9.1, 3.2, 2.4, 51.4, 1, 6.5, 5.6), o5 = c(3.3, 2.1, 0.6, 5.8, 0.4, 66.8, 9.4), o6 = c(1.4, 7.4, 8.8, 0.3, 64.5, 2, 5.4), o7 = c(3.6, 3.9, 4.3, 6.6, 8.3, 9.9, 51)), row.names = c(NA, -7L), class = c("tbl_df", "tbl", "data.frame"))

To show this graphically, I want to plot a flipped, stacked bar chart - similar to this one: enter image description here (Taken from this post: Add percentage labels to stacked bar chart ggplot2)

Instead of County, I want to depict the different types of birds on the x-axis (type), instead of Plan Types I want to fill the bar with the percentage of interactions between the different types of birds (o1-o7).

My questions now are:

  • How do I organize/group columns o1, o2, o3, o4, o5, o6, o7 to be used as fill?
  • What is my y?
ggplot() +
geom_bar(aes(y = ?, x = type, fill = ?),
         data = bird.data,
         stat="identity") +
         coord_flip()

Thanks a lot in advance for any advice! :-)

EDIT: I have implemented the great suggestions by stefan, and now encountered another problem:

When adding labels to the stacked bar chart, vjust=0.5 does not place them in the middle of the respective bar:

```
ggplot() +
  geom_col(aes(x = value, y = type, fill = name), 
           data = bird_data_long,
           position = position_stack(reverse = TRUE)) +
  scale_y_discrete(limits=rev) +
  geom_label(data = subset(bird_data_long, value > 10), 
            aes(x = value, y = type, label = paste0(round(value, digits = 0),"%")), 
            size = 3, position = position_stack(vjust = 0.5))
```

The plot looks like this: Stacked Bar with Labels

My question therefore is: how can I adjust the position of the labels so that they are placed exactly in the middle of the bar they are representing? Any idea why they are skewed? Any advice is much appreciated!

30163
  • 15
  • 5

1 Answers1

2

You could achieve your desired result by converting your data to long format using e.g. tidyr::pivot_longer. Afterwards it's pretty straightforward what should be mapped on fill and y.

Note: Instead of geom_bar(.. stat="identity") I use geom_col(...). Also instead of coord_flip I switched the role of x and y.

library(tidyr)
library(ggplot2)

bird_data_long <- bird.data %>% 
  pivot_longer(-type, names_to = "name", values_to = "value")

head(bird_data_long)
#> # A tibble: 6 × 3
#>   type  name  value
#>   <chr> <chr> <dbl>
#> 1 t1    o1     77.6
#> 2 t1    o2      3.5
#> 3 t1    o3      1.5
#> 4 t1    o4      9.1
#> 5 t1    o5      3.3
#> 6 t1    o6      1.4

ggplot() +
  geom_col(aes(x = value, y = type, fill = name), data = bird_data_long)

EDIT The main issue is that you subsetted the data in geom_text. Hence you are stacking a different set of values compared to the bars so that the positions of the labels no longer correspond to the positions of the bars. To get rid of labels for smaller bars use an ifelse instead. This way your labels are placed at the correct positions.

ggplot() +
  geom_col(aes(x = value, y = type, fill = name), 
           data = bird_data_long,
           position = position_stack(reverse = TRUE)) +
  scale_y_discrete(limits=rev) +
  geom_label(data = bird_data_long, 
             aes(x = value, y = type, group = name, label = ifelse(value > 10, paste0(round(value, digits = 0),"%"), NA)), 
             size = 3, position = position_stack(vjust = 0.5,reverse = TRUE), na.rm = TRUE)

stefan
  • 90,330
  • 6
  • 25
  • 51
  • Thanks a lot, that was super helpful! How would you proceed to show labels on the stacked bars? If I use geom_text like this: ```geom_text(data = bird_data_long, x = value, y = type, label = value, size = 3, position = position_stack(vjust = 0.5))``` I receive the error: Error in layer(data = data, mapping = mapping, stat = stat, geom = GeomText, : object 'value' not found. Any idea why value is not recognized? – 30163 Mar 06 '22 at 15:36
  • 1
    You have to wrap the mapping in `aes()`: `geom_text(data = bird_data_long, aes(x = value, y = type, label = value), size = 3, position = position_stack(vjust = 0.5))` – stefan Mar 06 '22 at 17:28
  • Any idea about my edit above? – 30163 Mar 26 '22 at 11:23
  • See my edit: Never subset your data when stacking. (; – stefan Mar 26 '22 at 12:08