Different fill orders in geom_bar per discrete x-value

十年热恋 提交于 2021-02-19 02:57:25

问题


I have this ggplot:

pic

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 that cat1, followed by k, then j etc.
  • For cat1 == Y: j would come first, because it has the largest share in that cat1, followed by h, 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!