2

I was answering this question where @Léo wanted a barplot with stat = "identity" and position = "identity". This causes the bars (one for every value of the fill aesthetic) to get on top of eachother, making some to get hidden:

His solution was to set alpha = 0.5, but he didn't liked the result as the colors mixed in different ways in each x-axis tick. Thus, i figured that the solution would be to have a different color ordering for each x-axis tick, but i don't know how to do it in ggplot.

What I've tried:

Dummy data:

library(tidyverse)
set.seed(7)

df = tibble(
  categories = rep(c("a", "b", "c"), each = 3) %>% factor(),
  xaxis = rep(1:3, 3) %>% factor(),
  yaxis = runif(9))

What plotted the "original" graph, shown above:

ggplot() +
  geom_bar(aes(xaxis, yaxis, fill = categories), df,
           stat = "identity", position = "identity")

My attempt: changing the categories levels order and creating a different geom_bar for each x-axis value with a for loop:

g = ggplot()

for(x in unique(df$xaxis)){
  df.x = df %>% filter(xaxis == x) %>% mutate(categories = fct_reorder(categories, yaxis))
  g = g + geom_bar(aes(xaxis, yaxis, fill = categories), df.x,
                   stat = "identity", position = "identity")}
plot(g)

The levels on df.x actually change to the correct order for every iteration, but the same graph as before gets produced.

2 Answers2

1

I draw a traditional overlapping plot and (if i understood correctly) your desired plot below to compare results:

library(tidyverse)
set.seed(7)

df = tibble(
  categories = rep(c("a", "b", "c"), each = 3) %>% factor(),
  xaxis = rep(1:3, 3) %>% factor(),
  yaxis = runif(9))

ggplot() +
  geom_bar(aes(xaxis, yaxis, fill = categories, group=categories), df, alpha=0.8,
           stat = "identity", position = position_dodge(width=0.3,preserve = "single"))

df<-df %>% group_by(xaxis) %>% mutate(rank=rank(-yaxis)) %>% 
  pivot_wider(values_from=yaxis, names_from = rank, values_fill = 0, 
              names_sort = T, names_prefix = "rank")

print(df)
#> # A tibble: 9 × 5
#> # Groups:   xaxis [3]
#>   categories xaxis rank1 rank2  rank3
#>   <fct>      <fct> <dbl> <dbl>  <dbl>
#> 1 a          1     0.989 0     0     
#> 2 a          2     0     0.398 0     
#> 3 a          3     0     0     0.116 
#> 4 b          1     0     0     0.0697
#> 5 b          2     0     0     0.244 
#> 6 b          3     0.792 0     0     
#> 7 c          1     0     0.340 0     
#> 8 c          2     0.972 0     0     
#> 9 c          3     0     0.166 0

g <- reduce(
  map(paste0("rank",1:3),
    ~geom_bar(aes(xaxis, .data[[.x]], fill=categories), stat="identity", position="identity")), 
    `+`, .init = ggplot(df) )

g

Created on 2022-11-02 with reprex v2.0.2

EDIT

It is easier, thanks to Park and this post

set.seed(7)

df = tibble(
  categories = rep(c("a", "b", "c"), each = 3) %>% factor(),
  xaxis = rep(1:3, 3) %>% factor(),
  yaxis = runif(9))

df %>% group_by(xaxis) %>% arrange(rank(-yaxis)) %>% 
ggplot() + geom_bar(aes(xaxis, yaxis, fill=categories), stat="identity", position="identity")
Ric
  • 5,362
  • 1
  • 10
  • 23
1

How about this?

df %>%
  arrange(xaxis, yaxis) %>%
  group_by(xaxis) %>%
  mutate(yaxis = yaxis - lag(yaxis, default = 0)) %>%
  ggplot() +
  geom_bar(aes(xaxis, yaxis, fill = categories),
           stat = "identity", position = "stack")

enter image description here

Park
  • 14,771
  • 6
  • 10
  • 29
  • Nice solution! What i had in mind was more in line with Ric Villalba's second option (I could've been more specific in what was my intended output), but thanks anyway! – Ricardo Semião e Castro Nov 03 '22 at 01:00