for loop R markdown plots "not a multiple of replacement length"

Hello

I would like to create a for loop to automatically render the same plot for different "names" in html Rmarkdown. I believe the library used is library(tidyverse).

example <- data.frame(
  number = as.numeric(c("1", "6", "12", "2", "3", "5", "53")),
  variable = c("Low", "Low", "Low", "Normal", "Exaggerated", "Exaggerated", "NA"),
  date = as.Date(c("1991-01-08", "1991-02-05", "1991-03-05", "1991-01-13", "1991-01-15", "1991-01-29", "NA")),
  words = rep("NA", 7),
  second_number = c("20", "10", "5", "100", "20", "5", "NA"),
  third_number = c("20", "10", "5", "99", "20", "5", "NA"),
  name = c( "Aname", "Aname", "Aname", "Cname", "Cname", "Cname", "IGNORE"),
  fourth_number = c("20", "7", "5", "97", "19", "5", "NA"),
  fifth_number = c("0", "0", "0", "0", "0", "0", "NA"),
  sixth_number = c("0", "3", "0", "2", "1", "0", "NA"),
  seventh_number = c("0", "0", "0", "0", "0", "0", "NA"),
  more_words = rep("NA", 7),
  eighth_number = as.numeric(c("1.0", "0.7", "0.1", "0.979", "0.950", "1.000", "NA")),
  stringsAsFactors = FALSE
)

example <- example[order(example$number), ]

example_plot <- NULL

for (i in 1:length(unique(example$name))) { 
  example_plot[i] <- example |> filter(name == (unique(example$name))[i]) |>
    ggplot(aes(date, eighth_number, group = variable, 
               color = variable,
               show_guide = TRUE)) +
    geom_point(size = 1) + 
    labs(title = (unique(example$name))[i], x = 'date', y = 'eighth number') + 
    geom_line() +
    theme_bw() +
    scale_x_date(date_labels = "%b %Y", date_breaks = "month") +
    geom_label_repel(aes(label = format(date, format = "%b %d")),
                     size = 3,
                     hjust=0.5, 
                     vjust=1,
                     angle=90,
                     box.padding   = 0.25, 
                     point.padding = 0.5,
                     segment.color = 'grey50')
  print(example_plot[i])
}

Instead of generating the plots, R prints the table for each "name".

This is an issue I run into for both RStudio and RMarkdown. I get the warning message:
1: In example_plot[i] <- ggplot(filter(example, name == (unique(example$name))[i]), :
number of items to replace is not a multiple of replacement length
2: In example_plot[i] <- ggplot(filter(example, name == (unique(example$name))[i]), :
number of items to replace is not a multiple of replacement length
3: In example_plot[i] <- ggplot(filter(example, name == (unique(example$name))[i]), :
number of items to replace is not a multiple of replacement length

I would also appreciate tips to improve on errors in my for loop syntax. Thank you

I'm not good with using for loops in R, however this looks like it might work with the purrr::map function.

# package library
library(tidyverse)

# sample data
example <- data.frame(
  number = as.numeric(c("1", "6", "12", "2", "3", "5", "53")),
  variable = c("Low", "Low", "Low", "Normal", "Exaggerated", "Exaggerated", "NA"),
  date = as.Date(c("1991-01-08", "1991-02-05", "1991-03-05", "1991-01-13", "1991-01-15", "1991-01-29", "NA")),
  words = rep("NA", 7),
  second_number = c("20", "10", "5", "100", "20", "5", "NA"),
  third_number = c("20", "10", "5", "99", "20", "5", "NA"),
  name = c("Aname", "Aname", "Aname", "Cname", "Cname", "Cname", "IGNORE"),
  fourth_number = c("20", "7", "5", "97", "19", "5", "NA"),
  fifth_number = c("0", "0", "0", "0", "0", "0", "NA"),
  sixth_number = c("0", "3", "0", "2", "1", "0", "NA"),
  seventh_number = c("0", "0", "0", "0", "0", "0", "NA"),
  more_words = rep("NA", 7),
  eighth_number = as.numeric(c("1.0", "0.7", "0.1", "0.979", "0.950", "1.000", "NA")),
  stringsAsFactors = FALSE
)
#> Warning in data.frame(number = as.numeric(c("1", "6", "12", "2", "3", "5", :
#> NAs introduced by coercion

# sort sample data order by number
example <- example[order(example$number), ]

# for sake of the example, see what the data looks like when filtered
# by each name variable 
map(
  .x = unique(example$name),
  .f = ~filter(example, name == .x)
)
#> [[1]]
#>   number variable       date words second_number third_number  name
#> 1      1      Low 1991-01-08    NA            20           20 Aname
#> 2      6      Low 1991-02-05    NA            10           10 Aname
#> 3     12      Low 1991-03-05    NA             5            5 Aname
#>   fourth_number fifth_number sixth_number seventh_number more_words
#> 1            20            0            0              0         NA
#> 2             7            0            3              0         NA
#> 3             5            0            0              0         NA
#>   eighth_number
#> 1           1.0
#> 2           0.7
#> 3           0.1
#> 
#> [[2]]
#>   number    variable       date words second_number third_number  name
#> 1      2      Normal 1991-01-13    NA           100           99 Cname
#> 2      3 Exaggerated 1991-01-15    NA            20           20 Cname
#> 3      5 Exaggerated 1991-01-29    NA             5            5 Cname
#>   fourth_number fifth_number sixth_number seventh_number more_words
#> 1            97            0            2              0         NA
#> 2            19            0            1              0         NA
#> 3             5            0            0              0         NA
#>   eighth_number
#> 1         0.979
#> 2         0.950
#> 3         1.000
#> 
#> [[3]]
#>   number variable date words second_number third_number   name fourth_number
#> 1     53       NA <NA>    NA            NA           NA IGNORE            NA
#>   fifth_number sixth_number seventh_number more_words eighth_number
#> 1           NA           NA             NA         NA            NA
 
# back to the question at hand
# use of map instead of for loop
map(
  # for each variable in .x
  .x = unique(example$name), 
  # do .f 
  .f = ~ filter(example, name == .x) %>% # filter by .x
    ggplot( # plot 
    mapping = aes(
      x = date,
      y = eighth_number,
      group = variable,
      color = variable
    )
  ) +
    geom_point(size = 1) +
    labs(
      title = str_c(.x),
      x = "date",
      y = "eighth number"
    ) +
    geom_line() +
    theme_bw() +
    scale_x_date(date_labels = "%b %Y", date_breaks = "month")
)
#> [[1]]

#> 
#> [[2]]

#> 
#> [[3]]
#> Error in seq.int(r1$mon, 12 * (to0$year - r1$year) + to0$mon, by): 'from' must be a finite number

Created on 2024-02-21 with reprex v2.0.2

Hi Rene, Thank you for your idea! However, with the map option I get another error:

#> Error in seq.int(r1$mon, 12 * (to0$year - r1$year) + to0mon, by):
#> 'from' must be a finite number
#> Calls: <Anonymous> ... as.Date -> cut -> cut.Date -> as.Date -> seq -> seq.POSIXt
#> Execution halted 

Therefore, none of the plots display.

Do you know what could be causing the error?

In the example data provided, there are only "NA" values for example$name == "IGNORE". Meaning, that's what the error is stating. "NA" is not a finite number and the function cannot be executed for that variable. However, it does execute for the first two variables, c("Aname", "Cname").

Alternatively, you could filter out the "IGNORE" values before sending it to the function:

# package library
library(tidyverse)

# sample data
example <- data.frame(
  number = as.numeric(c("1", "6", "12", "2", "3", "5", "53")),
  variable = c("Low", "Low", "Low", "Normal", "Exaggerated", "Exaggerated", "NA"),
  date = as.Date(c("1991-01-08", "1991-02-05", "1991-03-05", "1991-01-13", "1991-01-15", "1991-01-29", "NA")),
  words = rep("NA", 7),
  second_number = c("20", "10", "5", "100", "20", "5", "NA"),
  third_number = c("20", "10", "5", "99", "20", "5", "NA"),
  name = c("Aname", "Aname", "Aname", "Cname", "Cname", "Cname", "IGNORE"),
  fourth_number = c("20", "7", "5", "97", "19", "5", "NA"),
  fifth_number = c("0", "0", "0", "0", "0", "0", "NA"),
  sixth_number = c("0", "3", "0", "2", "1", "0", "NA"),
  seventh_number = c("0", "0", "0", "0", "0", "0", "NA"),
  more_words = rep("NA", 7),
  eighth_number = as.numeric(c("1.0", "0.7", "0.1", "0.979", "0.950", "1.000", "NA")),
  stringsAsFactors = FALSE
) %>%
  as_tibble() %>%
  filter(name != "IGNORE")
#> Warning in data.frame(number = as.numeric(c("1", "6", "12", "2", "3", "5", :
#> NAs introduced by coercion

Created on 2024-02-26 with reprex v2.0.2

This topic was automatically closed 42 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.