问题
I have this ggplot:
What I want to do is change the order of cat2
in each distinct cat1
-category in decreasing order of share
:
- For cat1 == Z:
i
would come first, because it has the largest share in thatcat1
, followed byk
, thenj
etc. - For cat1 == Y:
j
would come first, because it has the largest share in thatcat1
, followed byh
,k
,f
,g
- and so on for all cat1-categories.
I know I can control the order by defining factor levels, but since I need a different order in different cat1-categories, I'm not sure how to do this.
Can someone enlighten me?
df <- structure(list(cat2 = c("i", "k", "j", "h", "g", "j", "h", "k",
"f", "g", "j", "h", "k", "f", "g", "i", "k", "j", "h", "f"),
cat1 = c("Z", "Z", "Z", "Z", "Z", "Y", "Y", "Y", "Y", "Y",
"X", "X", "X", "X", "X", "W", "W", "W", "W", "W"), share = c(0.254318086442458,
0.217254586570476, 0.13303361614456, 0.107317457057957, 0.0796390207719751,
0.255762968963295, 0.198921069216629, 0.177295815678624,
0.100770340584133, 0.0971042138291394, 0.222007778896866,
0.177174367182501, 0.156891912894117, 0.097677432116308,
0.0975337223454565, 0.503295513011454, 0.154491050393999,
0.114284166914891, 0.0802892036069214, 0.0549053589320047
), pos = c(0.477447245936265, 0.108627293285238, 0.283771394642756,
0.658265017686473, 0.751743256601439, 0.305177300160272,
0.532519319250233, 0.088647907839312, 0.779469237979754,
0.680531960773118, 0.26789580234255, 0.467486875382234, 0.0784459564470585,
0.702446497377094, 0.604840920146212, 0.520422973814617,
0.0772455251969995, 0.211633133851444, 0.812215332123805,
0.879812613393268)), .Names = c("cat2", "cat1", "share",
"pos"), class = "data.frame", row.names = c(NA, -20L))
library(ggplot2)
ggplot(df, aes(cat1, share)) +
geom_bar(stat = "identity", aes(fill = cat2)) +
geom_text(aes(label = cat2, y = pos)) +
coord_flip()
Note: my current thinking is that perhaps it could be done using a new category with the levels set as 1st, 2nd, 3rd, 4th, 5th but if I use that for filling, different cat2-values for example i
for Z
and j
for Y
would have the same fill-color because they are 1st in the respective cat1-category which I wouldn't want.
回答1:
You can do this by creating a new factor column, let's call it cat3
, based on both cat1
and cat2
. Set the factor ordering of this column based on cat1
and share
. Then use this new cat3
factor column as a group
aesthetic to set the stacking order for the bars.
In the code below, arrange
sets the ordering. We sort the data frame by share
separately within each level of cat1
. Now the data frame is in the order we want. Then we create cat3
by pasting cat1
and cat2
together and set the order of the levels to be the current sorted order of the data frame. Finally, within ggplot
we use cat3
as a group
aesthetic to set the stacking order in geom_bar
.
Another addition is the use of position_stack(vjust=0.5)
to set the label locations, rather than a y
aesthetic.
library(tidyverse)
df %>%
arrange(cat1, share) %>%
mutate(cat3 = factor(paste(cat1, cat2), levels=paste(cat1, cat2))) %>%
ggplot(aes(cat1, share, group=cat3)) +
geom_bar(stat = "identity", aes(fill = cat2)) +
geom_text(aes(label = cat2), position=position_stack(vjust=0.5)) +
coord_flip()
来源:https://stackoverflow.com/questions/46201308/different-fill-orders-in-geom-bar-per-discrete-x-value