How to show bars in ggplot2 in descending order of a numeric vector?
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
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.
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)))