I\'m facing a behaviour of ggplot2
, ordering and stacked barplot that I cannot understand.
I\'ve read some question about it (here,here and so on), but unlu
If you use separate geom_bar
s, you can make the orders different.
dats %>%
ggplot(aes(x = id, y = value, fill = reorder(filling,-ordering))) +
geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 1)) +
geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 2)) +
geom_bar(stat = "identity", position = "stack", data = dats %>% filter(id == 3)) +
guides(fill=guide_legend("ordering"))
More generally:
bars <- map(unique(dats$id)
, ~geom_bar(stat = "identity", position = "stack"
, data = dats %>% filter(id == .x)))
dats %>%
ggplot(aes(x = id, y = value, fill = reorder(filling,-ordering))) +
bars +
guides(fill=guide_legend("ordering"))
The problem is that, in your case, different bars should use the same values (levels) of filling
in a different order. This conflicts with the way ggplot
works: taking the factor levels (which already have a certain order) and applying them in the same way for each bar.
A workaround then is... To create many factor levels.
ggplot(dats, aes(x = id, y = value, fill = interaction(-ordering, id))) +
geom_bar(stat = "identity", position = "stack")
This one now is too "generous" by being too detailed. However, what we can do now is to deal with the legend and the different colors:
dats <- arrange(dats, id, -ordering)
aux <- with(dats, match(sort(unique(filling)), filling))
ggplot(dats, aes(x = id, y = value, fill = interaction(-ordering, id))) +
geom_bar(stat = "identity", position = "stack") +
scale_fill_manual("Ordering", values = scales::hue_pal()(4)[dats$filling],
labels = with(dats, filling[aux]),
breaks = with(dats, interaction(-ordering, id)[aux]))
Here I first rearrange the rows of dats
as to avoid doing that later. Then aux
is an auxiliary vector
aux
# [1] 3 2 1 8
giving arbitrary positions (one for each) where levels a
, b
, c
, and d
(in this order) appear in dats
, which again is useful later. Then I simply set corresponding scale values, labels, and breaks... Lastly, I use scales::hue_pal
to recover the original color palette.
The problem here is that the element filling = d
only appears in the third group with a low value. One solution, could be to fill non-present values with 0:
library(dplyr)
#>
#> Attachement du package : 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
library(ggplot2)
dats <- data.frame(id = c(1,1,1,1,2,2,2,2,3,3,3,3),
value = c(9,6,4,0,5,6,0,0,4,3,4,5),
ordering = c(1,2,3,5,2,3,5,5,1,3,2,4),
filling = c('a','b','c','d','b','a','c','d','a','c','d','b')) %>% arrange(id,ordering)
ggplot(dats,aes(x = id,
y = value,
fill = reorder(filling,-ordering))) +
geom_bar(stat = "identity",position = "stack") +
guides(fill=guide_legend("ordering"))
Created on 2018-12-03 by the reprex package (v0.2.1)