1

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!

Tathagato
  • 348
  • 1
  • 11

1 Answers1

2

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

Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
  • Thanks! This worked perfectly until I ran into a weird problem. I can't seem to manage how to put the weeks in order. For example, following your method, I get a nice bargraph, but the weeks are ordered as w1, w11:19, w2, w21:29, w3, w31:35, whereas the columns in the data are ordered in ascending order (w1:w35). Any lead on how to change this to the right order that follows the order of columns in the data? – Tathagato Sep 30 '22 at 19:18
  • 1
    @Tathagato Use package `stringr`, function `str_sort` with argument `numeric=TRUE` to put the unique values in order then coerce to factor with those values as factors. I will post code later on today – Rui Barradas Sep 30 '22 at 22:16
  • 1
    @Tathagato Done, see the edit. – Rui Barradas Sep 30 '22 at 23:23