Home > front end >  Bar plot in loop for each observation
Bar plot in loop for each observation

Time:10-01

Here is sample data where ID is a categorical variable.

ID <- c(12, 34, 560, 45, 235)
W1 <- c(0, 5, 7, 6, 0)
W2 <- c(7, 8, 9, 5, 2)
W3 <- c(0, 0, 3, 5, 9)
 
df <- data.frame(ID, W1, W2, W3)
df$ID <- as.factor(df$ID)

I want to draw five bar plots for each of these IDs using the frequency data for the three weeks W1:W3. In the actual dataset, I have 30 weeks and around 150 IDs, hence the intention here is to do this efficiently. Nothing fancy, but ggplot would be ideal as I would need to manipulate some aesthetics.

How to do this using loop and save the images in one file(pdf)?

Thanks for your help!

CodePudding user response:

This sort of problem is usually a data reformating problem. See reshaping data.frame from wide to long format. After reshaping the data, the plot is faceted by ID, avoiding loops.

library(ggplot2)

ID <- c(12, 34, 560, 45, 235)
W1 <- c(0, 5, 7, 6, 0)
W2 <- c(7, 8, 9, 5, 2)
W3 <- c(0, 0, 3, 5, 9)

df <- data.frame(ID, W1, W2, W3)
df$ID <- as.factor(df$ID)
df[-1] <- lapply(df[-1], as.integer)

df |>
  tidyr::pivot_longer(-ID, names_to = "Week", values_to = "Frequency") |>
  ggplot(aes(Week, Frequency, fill = Week))  
  geom_col()  
  scale_y_continuous(breaks = scales::pretty_breaks())  
  facet_wrap(~ ID)  
  theme_bw(base_size = 16)

Created on 2022-09-30 with reprex v2.0.2


Edit

If there is a mix of week numbers with 1 and 2 digits, the lexicographic order is not the numbers' order. For instance, after W1 comes W11, not W2. Package stringr function str_sort sorts by numbers when argument numeric = TRUE.
In the example below I reuse the data changing W2 to W11. The correct bars order should therefore be W1, W3, W11.

library(ggplot2)
library(stringr)

ID <- c(12, 34, 560, 45, 235)
W1 <- c(0, 5, 7, 6, 0)
W11 <- c(7, 8, 9, 5, 2)
W3 <- c(0, 0, 3, 5, 9)

df <- data.frame(ID, W1, W11, W3)
df$ID <- as.factor(df$ID)
df[-1] <- lapply(df[-1], as.integer)

df |>
  tidyr::pivot_longer(-ID, names_to = "Week", values_to = "Frequency") |>
  dplyr::mutate(Week = factor(Week, levels = str_sort(unique(Week), numeric = TRUE))) |>
  ggplot(aes(Week, Frequency, fill = Week))  
  geom_col()  
  scale_y_continuous(breaks = scales::pretty_breaks())  
  facet_wrap(~ ID)  
  theme_bw(base_size = 16)

Created on 2022-10-01 with reprex v2.0.2

  • Related