Here is data of sales by year and model. Now I wan to rank/order these models by following:
Models has to be ordered from top to down according to their sales in each year. For example, E had the biggest sales in 2015, so it must the on the TOP, while in 2017 H must be on the TOP.
Moreover, I need to keep model J always on the bottom regardless its share.
library(dplyr)
library(ggplot2)
df <- data.frame (model = c("A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J","A","B","C","D","E","F","G","H","I","J"),
Year = c(2015,2015,2015,2015,2015,2015,2015,2015,2015,2015,2016,2016,2016,2016,2016,2016,2016,2016,2016,2016,2017,2017,2017,2017,2017,2017,2017,2017,2017,2017,2018,2018,2018,2018,2018,2018,2018,2018,2018,2018),
sales = c(450,678,456,344,984,456,234,244,655,789,234,567,234,567,232,900,1005,1900,450,345,567,235,456,345,144,333,555,777,111,444,222,223,445,776,331,788,980,1003,456,434))
df %>%
group_by(Year) %>%
mutate(Share = sales / sum(sales)) %>%
mutate_at(vars(Share), funs(round(., 4))) %>%
ggplot(aes(fill=model, y=Share, x=Year))
scale_x_continuous(breaks=seq(min(df$Year),max(df$Year),2))
geom_col(position="fill", width = 1, color = "white")
geom_text(aes(label = scales::percent(Share, accuracy = 0.1)),
position = position_fill(vjust = 0.50),
color = "black",size = 2)
scale_y_continuous(labels = scales::percent)
CodePudding user response:
You need to add the stacked columns per year to be able to use individual sorting on each column. Making use of some tidyverse
helpers you can try the following:
library(purrr)
library(forcats)
## split the data according to year and order factors according to need
## df_agg will eb a list(!) of data frames where each model is sorted accordingly
## Adding `Year2` is a quick hack as `group_map` drops the grouping variable
df_agg <- df %>%
group_by(Year) %>%
mutate(Share = sales / sum(sales), Year2 = Year) %>%
mutate(across(Share, ~ round(., 4))) %>%
group_by(Year) %>%
group_map(~ .x %>%
mutate(model = fct_reorder(model, Share, .desc = TRUE) %>%
fct_relevel("J", after = Inf)) %>%
rename(Year = Year2))
## base plot
bp <- ggplot()
scale_x_continuous(breaks = seq(min(df$Year), max(df$Year), 2))
scale_y_continuous(labels = scales::percent)
## use purrr::reduce to add geoms for each year to the baseplot
reduce(df_agg, ~ .x
geom_col(aes(x = Year, y = Share, fill = model), data = .y,
position = "fill", width = 1, color = "white")
geom_text(aes(x = Year, y = Share, fill = model,
label = scales::percent(Share, accuracy = 0.1)),
data = .y,
position = position_fill(vjust = 0.50),
color = "black", size = 2), .init = bp)
N.B. Personally, I find the plot hard to read as you always need to refer to the legend to determine which model is shown.