How to show bars in ggplot2 in descending order of

2020-05-23 08:33发布

df <- data.frame (Categories=c("Alpha Category", "Alpha Category", 
                               "Alpha Category", "Bravo Category", 
                               "Bravo Category", "Bravo Category", 
                               "Charlie Category", "Charlie Category", 
                               "Charlie Category"),  
                  choices=c("alpha1", "alpha2", "alpha3", "bravo1", 
                            "bravo2", "bravo3", "charlie1", "charlie2",
                            "charlie3")  , 
                  ratings=c(20,60,40, 55,75,25,65,35,45))    
df.plot <- ggplot(df, aes(Categories, ratings, fill = choices))
           + geom_bar(position="dodge", stat="identity") 
           + coord_flip()    
df.plot <- df.plot 
           + theme_classic(base_size = 16, base_family = "")  
           + scale_fill_brewer(palette="Paired")    
df.plot <- df.plot 
           + scale_y_continuous(breaks=seq(0,100,by=10),limits=c(0,80) )  
           + ylab("Ratings")  
           + theme(axis.text.y = element_text(size=16)) #change font size of y axis label   
df.plot

Most importantly, I would like to show the "choices" within each "category" in descending order of their "ratings", for example here "Charlie Category" would show charlie1, then charlie3, then charlie2.

I have honestly looked online for solutions for about a week but can't find it. My current thoughts is that I should convert the choices into factors but I haven't figured out how to do this properly.

Of secondary importance, it would be great if the "categories" could be listed, from the top down, "Alpha Category", "Bravo category", "Charlie Category" rather than in the inverse order as seems to occur when coordinates are flipped

标签: r ggplot2 rank
2条回答
成全新的幸福
2楼-- · 2020-05-23 08:56

This answer does not make use of the possibilities in ggplot to transform variables and scales (see @Metric's clean answer), but instead variables are transformed in beforehand.

Within each Category, reorder choices based on ratings. Check that 'choices' is a character. If it is a factor, you should convert to character with as.character, because reordering with a factor as input does not give us what we want (see below).

str(df$choices)
# chr [1:9] "alpha1" "alpha2" "alpha3" ...

library(plyr)
df <- ddply(.data = df, .variables = .(Categories), mutate,
            choices = reorder(choices, ratings))

Reverse levels of 'Categories'

df$Categories <- as.factor(df$Categories)
levels(df$Categories) <- rev(levels(df$Categories))

Plot

df.plot <- ggplot(df, aes(x = Categories, y = ratings, fill = choices)) +
  geom_bar(position = "dodge", stat = "identity") +
  coord_flip() +
  theme_classic(base_size = 16, base_family = "") +
  scale_fill_brewer(palette = "Paired") +
  scale_y_continuous(breaks = seq(0, 100, by = 10), limits = c(0, 80)) +
  ylab("Ratings")  +
  theme(axis.text.y = element_text(size = 16))   

df.plot

enter image description here

Edit following a comment from @Michael Bellhouse - "it appears alpha category is ranked but not bravo or charlie"

When 'choices' is a character, the factor levels that are generated and reordered in ddply is based on each subset of 'choices'. Which works fine. On the other hand, when 'choices' is a factor in the original data, its levels are based on all levels present in the data. In ddply subset of 'choice' levels are then reordered, but the reordering takes place within the full set of levels. This leads to three sets of conflicting levels and only the first is used.

# reorder character version
ll <- dlply(.data = df, .variables = .(Categories), mutate,
            choices.ro = reorder(choices, ratings))

# check levels
lapply(ll, function(x) levels(x$choices.ro))
# $`Alpha Category`
# [1] "alpha1" "alpha3" "alpha2"
# 
# $`Bravo Category`
# [1] "bravo3" "bravo1" "bravo2"
# 
# $`Charlie Category`
# [1] "charlie2" "charlie3" "charlie1"


# choices as factor
df$choices.fac <- as.factor(df$choices)
levels(df$choices.fac)
# [1] "alpha1"   "alpha2"   "alpha3"   "bravo1"   "bravo2"   "bravo3"   "charlie1" "charlie2"
# [9] "charlie3"

# reorder factor version
ll <- dlply(.data = df, .variables = .(Categories), mutate,
            choices.fac.ro = reorder(choices.fac, ratings))

# reordering takes place _within_ each Category, but on the _full set_ of levels
# $`Alpha Category`
# [1] "alpha1"   "alpha3"   "alpha2"   "bravo1"   "bravo2"   "bravo3"   "charlie1" "charlie2"
# [9] "charlie3"
# This set of levels will be used in ggplot if you start with choices as a factor.
# Hence @Michael Bellhouse comment: "alpha category is ranked but not bravo or charlie"

# $`Bravo Category`
# [1] "bravo3"   "bravo1"   "bravo2"   "alpha1"   "alpha2"   "alpha3"   "charlie1" "charlie2"
# [9] "charlie3"
# 
# $`Charlie Category`
# [1] "charlie2" "charlie3" "charlie1" "alpha1"   "alpha2"   "alpha3"   "bravo1"   "bravo2"  
# [9] "bravo3"

# Because a factor only can have one set of levels,
# the first set is used - $`Alpha Category`
# Thus, relordered within category Alpha only.
查看更多
地球回转人心会变
3楼-- · 2020-05-23 09:01
library(ggplot2)
df.plot <- ggplot(df, aes(x=Categories,y=reorder(choices,ratings), fill = choices)) +
  geom_bar(position = "dodge", stat = "identity") + coord_flip() +
  scale_x_discrete(limits = rev(levels(df$Categories)))

enter image description here

查看更多
登录 后发表回答