Reputation: 3292
Let's say I have an example data frame:
frame <-
data.frame(group = c(rep(1, 3), rep(2, 3)),
idea = c(1, 2, 3, 1, 2, 4),
value = c(10000, 5000, 50, 5000, 7500, 100),
level = sample(c("rough", "detailed"), 6, TRUE))
I'd like a barplot of values with each idea within a group ordered by it's value. I can get close like this
library(dplyr)
library(ggplot2)
top_ideas <-
frame %>%
group_by(group) %>%
arrange(group, desc(value))
frame %>%
group_by(group) %>%
mutate(idea = idea %>% factor(levels = top_ideas$idea)) %>%
ggplot(aes_string(x = "idea", y = "value", fill = "level")) +
geom_bar(stat = "identity") +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
facet_wrap(~group, scales = "free")
The mutate in the final dplyr
line is setting the factor levels according to their ordering in the top_ideas
dataframe above that. Unfortunately, because the idea nos 1 and 2 are shared by both groups 1 and 2, the ordering is set by the first group.
What I'd like to have is the ordering of ideas in both facets independent of each group. How can I do that in a dplyr
string? Am I missing something simple?
I should note that this is example data. The actual data is much larger and encompasses more groups and more ideas that are shared.
Upvotes: 2
Views: 3248
Reputation: 151
Here is a workaround with data.table
package.
Load packages:
library(data.table)
library(ggplot2)
Data:
# setting seed to make solution reproducible
set.seed(123)
frame <-
data.frame(group = c(rep(1, 3), rep(2, 3)),
idea = c(1, 2, 3, 1, 2, 4),
value = c(10000, 5000, 50, 5000, 7500, 100),
level = sample(c("rough", "detailed"), 6, TRUE))
Reorder factor levels by group:
top_ideas <- as.data.table(frame)
top_ideas[, grp_idea:= paste0(group, '_', idea)]
top_ideas[, grp_idea:= factor(grp_idea, levels = grp_idea[order(factor(group), -value)])]
Output data:
> top_ideas
group idea value level grp_idea
1: 1 1 10000 rough 1_1
2: 1 2 5000 rough 1_2
3: 1 3 50 rough 1_3
4: 2 1 5000 detailed 2_1
5: 2 2 7500 rough 2_2
6: 2 4 100 detailed 2_4
Plot:
top_ideas |>
ggplot(aes(x = grp_idea, y = value, fill = level)) +
geom_bar(stat = "identity") +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
facet_wrap(~group, scales = "free") +
xlab("idea") +
scale_x_discrete(breaks = top_ideas$grp_idea,
labels = top_ideas$idea)
Note: Although using the same set.seed
as the one in the accepted answer, it produced a different order of the level variable than that shown in the accepted answer.
Upvotes: 0
Reputation: 18681
Here is a workaround:
Data:
# setting seed to make solution reproducible
set.seed(123)
frame <-
data.frame(group = c(rep(1, 3), rep(2, 3)),
idea = c(1, 2, 3, 1, 2, 4),
value = c(10000, 5000, 50, 5000, 7500, 100),
level = sample(c("rough", "detailed"), 6, TRUE))
Code:
library(dplyr)
library(tidyr)
library(ggplot2)
top_ideas <-
frame %>%
group_by(group) %>%
arrange(group, desc(value)) %>%
unite("grp_idea", group, idea, sep = "_", remove = FALSE) %>%
data.frame() %>%
mutate(grp_idea = factor(grp_idea, levels = grp_idea))
top_ideas %>%
group_by(group) %>%
ggplot(aes(x = grp_idea, y = value, fill = level)) +
geom_bar(stat = "identity") +
theme(legend.position = "bottom",
axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1)) +
facet_wrap(~group, scales = "free") +
xlab("idea") +
scale_x_discrete(breaks = top_ideas$grp_idea,
labels = top_ideas$idea)
Results:
> top_ideas
grp_idea group idea value level
1 1_1 1 1 10000 rough
2 1_2 1 2 5000 detailed
3 1_3 1 3 50 rough
4 2_2 2 2 7500 detailed
5 2_1 2 1 5000 detailed
6 2_4 2 4 100 rough
Note:
Basically what I'm doing is to paste together group
and idea
variables, convert the new variable grp_idea
to a factor with the desired levels, and use that as the x-axis instead of the original idea
column. This ensures that the ordering of levels in each facet will not be affected by other facets since they no longer share the same levels. It is then easy enough to relabel the x-axis title and tick labels with xlab
and scale_x_discrete
.
Upvotes: 7