1

Considering a data frame as below that shows different types of activities happened within 5 weeks,

      id  Type     Day_index(no)
 1   711  C        16
 2   346  A        30 
 3   569  B        8  
 4    11  A        22 
 5   263  A        29 
 6   510  C        19 
 7   686  B        9  
 8   467  A        11 
 9   478  C        16 
10   202  A        22
11   701  C        22 
12   448  A        5  
13   106  A        19 
14   674  B        8  
15   139 A         25 

How to plot a percentage Stacked Bar Plot in r which x-axis shows weeks and day names instead of the day number in the data frame as below:

enter image description here

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
Sean
  • 103
  • 9

1 Answers1

2

Maybe this is closer to what you need :

library(dplyr)
library(ggplot2)

#Days of the week
days <- c("Monday","Tuesday","Wednesday","Thursday","Friday", "Saturday","Sunday")

df %>% 
 mutate(week = paste('Week', ceiling(Day_index/7)), 
        day = factor(days[Day_index %% 7], levels = days)) %>% 
 add_count(week, day) %>% 
 group_by(week) %>%
 mutate(n = round(n/sum(n) * 100, 2)) %>%
 ggplot() + aes(day, n, fill = Type, label = paste(n, "%")) + 
 geom_bar(stat = "identity") + 
 facet_grid(.~week) + 
 scale_x_discrete(drop=FALSE) + 
 geom_text(size = 3, position = position_stack(vjust = 0.5)) + 
 theme(axis.text.x = element_text(angle = 45, hjust = 1))

enter image description here

(Included some suggestion from @dc37 for better visibility.)

data

df <- structure(list(id = c(711L, 346L, 569L, 11L, 263L, 510L, 686L, 
467L, 478L, 202L, 701L, 448L, 106L, 674L, 139L), Type = structure(c(3L, 
1L, 2L, 1L, 1L, 3L, 2L, 1L, 3L, 1L, 3L, 1L, 1L, 2L, 1L), .Label = c("A", 
"B", "C"), class = "factor"), Day_index = c(16L, 30L, 8L, 22L, 
29L, 19L, 9L, 11L, 16L, 22L, 22L, 5L, 19L, 8L, 25L)), class = 
"data.frame", row.names = c("1", "2", "3", "4", "5", "6", "7", "8", "9", "10", 
 "11", "12", "13", "14", "15"))
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Thanks you so much. Can't these 5 weeks to be plotted in a row, please? – Sean Dec 11 '19 at 07:58
  • 1
    Nice solution ! Just a personal suggestion, using `facet_grid(.~week)` will align all weeks horizontally (making closer to the image provided by the OP). Also, if you use `theme(axis.text.x = element_text(angle = 45, hjust = 1))`, you have a better lisibility of days – dc37 Dec 11 '19 at 07:58
  • And one more point, When I said Stacked bar, I meant the scales of frequencies to be in percentages. Currently, it shows some of all at 100% each day. I want to see which day has most the most frequency of all. – Sean Dec 11 '19 at 08:01
  • @Sean You are not interested in `Type` ? – Ronak Shah Dec 11 '19 at 08:04
  • I mean stacked bar chart like the below instead if percent bar chart: https://stackoverflow.com/questions/21236229/stacked-bar-chart – Sean Dec 11 '19 at 08:05
  • @RonakShah, my pleasure !! (for once I'm able to help you ;)) – dc37 Dec 11 '19 at 08:11
  • @Sean I am not sure if I understand you, Do you mean total of all the bars in the week should be 100 ? So something like `df %>% mutate(week = paste('Week', ceiling(Day_index/7)), day = factor(days[Day_index %% 7], levels = days)) %>% group_by(week, day) %>% add_count(week, day) %>% group_by(week) %>% mutate(n = n/sum(n) * 100) %>% ggplot() + aes(day, n, fill = Type) + geom_bar(stat = "identity") + facet_grid(.~week) + scale_x_discrete(drop=FALSE) + theme(axis.text.x = element_text(angle = 45, hjust = 1))` ? – Ronak Shah Dec 11 '19 at 08:18
  • @Ronak, The y-axis should be frequencies of day_index, and scales as a percentage. – Sean Dec 11 '19 at 08:26
  • @Sean am I correct in assuming that `Day_index` is used to count the weekday and weeknumber ? Can you check if those data is correct ? This is another attempt : `df %>% mutate(week = paste('Week', ceiling(Day_index/7)), day = factor(days[Day_index %% 7], levels = days)) %>% group_by(week, day) %>% add_count(week, day) %>% ggplot() + aes(day, n, fill = Type) + geom_bar(stat = "identity") + facet_grid(.~week) + scale_x_discrete(drop=FALSE) + theme(axis.text.x = element_text(angle = 45, hjust = 1))` – Ronak Shah Dec 11 '19 at 08:35
  • @RonakShah, Yes, Seems it is almost what I meant. Just need the Y-axis to be percentages and the percentages of each colour to be labelled inside each bar. Much appreciated again. – Sean Dec 11 '19 at 08:48
  • @Sean See the updated answer, if it is what you need. You can play around with `size` and `position` argument of `geom_text` to suit your needs. – Ronak Shah Dec 11 '19 at 08:58
  • @RonakShah, For some reason it does not show the right scale (y-axis) when comparing with the simple barplot() results. Can you please advise how can I plot the same graph so that scales (y axis) to be similar to the barplot(df). Appreciate in advance. – Sean Dec 12 '19 at 06:36
  • @Sean I don't know what you mean, `barplot(df)` gives me `Error in barplot.default(df) : 'height' must be a vector or a matrix` – Ronak Shah Dec 12 '19 at 06:41
  • Try barplot(df$Day_index) – Sean Dec 12 '19 at 06:43
  • @Sean Please go through your previous comments, you said you need y-axis as percentage. Percentage has to be out of 100% , Y-axis of `barplot(df$Day_index)` is not percentage. – Ronak Shah Dec 12 '19 at 06:45
  • I see. Even percentage not correct l guess. How can i have the same but with frequency instead. – Sean Dec 12 '19 at 06:57
  • @Sean Percentages are correct. To get frequency `df %>% mutate(week = paste('Week', ceiling(Day_index/7)), day = factor(days[Day_index %% 7], levels = days)) %>% add_count(week, day) %>% select(-id) %>% distinct() %>% ggplot() + aes(day, n, fill = Type, label = n) + geom_bar(stat = "identity") + facet_grid(.~week) + scale_x_discrete(drop=FALSE) + geom_text(size = 3, position = position_stack(vjust = 0.5)) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) ` – Ronak Shah Dec 12 '19 at 07:02