1

I have a loop of 4 graphs with a character list like 'a, b, c, d', so in the title of each graph I want 'a', 'b', 'c' or 'd'. However, when I run my code, 'a' appears in all titles.

This is the dput of the data I am using.

structure(list(Point = c(5, 6, 7, 8), La = c(535, 565, 532, 587
), Ce = c(45, 46, 58, 43), Pr = c(56, 54, 43, 50), Nd = c(23, 
28, 18, 26)), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -4L), spec = structure(list(cols = list(
Point = structure(list(), class = c("collector_double", "collector"
)), La = structure(list(), class = c("collector_double", 
"collector")), Ce = structure(list(), class = c("collector_double", 
"collector")), Pr = structure(list(), class = c("collector_double", 
"collector")), Nd = structure(list(), class = c("collector_double", 
"collector"))), default = structure(list(), class = c("collector_guess", 
"collector")), skip = 1), class = "col_spec"))

and the code I came up so far. ONLY the cols do not cycle through the title. The rest of the code works perfectly. I am still a beginner, so thank you for your time and patience.

acq <- select(X1, La:Nd)

##loop##

gg <- for (ii in acq){
  cols <- names(X1)[2:5]
  m <-mean(ii)
  sds <- sd(ii)
  m1 <- mean(ii)+1
  m2 <-mean(ii)-1

  ##plot##  
  g <- ggplot(X1,aes_string(x="Point",y="ii")) +
    ggtitle(paste(cols,"\n",m,"\n",sds,"\n")) +
    theme(plot.title = element_text(hjust = 0.5)) +
    geom_line() + geom_hline(aes(yintercept=mean(ii))) + ylab('') + xlab('')+
    geom_hline(aes(yintercept=m1),linetype=2)  + 
    geom_text(x=8,y=m1,label="10%",vjust=-1) +
    geom_hline(aes(yintercept=m2),linetype=2) + 
    geom_text(x=8,y=m2,label="10%",vjust=-1)

  print(g)  
}

My data:

~Point, ~La, ~Ce, ~Pr, ~Nd,
     5, 535,  45,  56,  23,
     6, 565,  46,  54,  28,
     7, 532,  58,  43,  18,
     8, 587,  43,  50,  26
Tung
  • 26,371
  • 7
  • 91
  • 115
Yria
  • 23
  • 6
  • 1
    For [reproducibility](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example), please edit your question with the output from `dput(df)`. – Z.Lin Mar 16 '19 at 03:11
  • 1
    https://stackoverflow.com/a/55114232/786542 – Tung Mar 16 '19 at 03:18
  • @Tung I'm sorry but that code is too complicated for me to understand. – Yria Mar 16 '19 at 07:02
  • @Yria: Could you make your problem reproducible by sharing a sample of your data so others can help (please do not use `str()`, `head()` or screenshot)? You can use the [`reprex`](https://reprex.tidyverse.org/articles/articles/magic-reprex.html) and [`datapasta`](https://cran.r-project.org/web/packages/datapasta/vignettes/how-to-datapasta.html) packages to assist you with that. See also [Help me Help you](https://speakerdeck.com/jennybc/reprex-help-me-help-you?slide=5) & [How to make a great R reproducible example?](https://stackoverflow.com/q/5963269) – Tung Mar 16 '19 at 07:05
  • @Tung Thank you for suggestions. I added the dput, the actual code and the actual data I've been using to build the code. – Yria Mar 16 '19 at 07:21

1 Answers1

0

They way you setup the for-loop is not really recommended. It's better to loop through column names then extract that column from the acq data frame accordingly

library(tidyverse)

acq <- select(X1, La:Nd)

## loop ##
for (ii in seq_along(colnames(acq))) {

  current_col <- colnames(acq)[ii]
  print(paste0('Plot col: ', current_col))

  # calculate mean and stdev
  m <- mean(acq[[current_col]])
  sds <- sd(acq[[current_col]])
  m1 <- m + 1
  m2 <- m - 1

  ## plot ##
  g <- ggplot(X1, aes_string(x = "Point", y = current_col)) +
    ggtitle(paste("column = ", current_col, "\n", 
                  "mean = ", formatC(m, digits = 3), "\n",
                  "sd = ", formatC(sds, digits = 3), "\n")) +
    theme_classic(base_size = 12) +
    theme(plot.title = element_text(hjust = 0.5)) +
    geom_line() + 
    geom_hline(aes(yintercept = m)) + 
    ylab("") + xlab("") +
    geom_hline(aes(yintercept = m1), linetype = 2) +
    geom_text(x = 8, y = m1, label = "10%", vjust = -1, check_overlap = TRUE) +
    geom_hline(aes(yintercept = m2), linetype = 2) +
    geom_text(x = 8, y = m2, label = "10%", vjust = 2, check_overlap = TRUE)

  print(g)
}

Example output:

#> [1] "Plot col: La"

#> [1] "Plot col: Ce"

Another (preferable) way is to use the new tidy evaluation approach (more explanation here)

generate_plot2 <- function(df, .x.variable, .y.variable) {

  x.variable <- rlang::sym(.x.variable)
  y.variable <- rlang::sym(.y.variable)

  sum_df <- df %>% 
    summarise_at(vars(!!y.variable), funs(mean, sd)) %>% 
    mutate(m1 = mean + 1,
           m2 = mean - 1)
  print(sum_df)

  g <- ggplot(df, aes(x = !! x.variable, y = !! y.variable)) +
    ggtitle(paste("column = ", .y.variable, "\n", 
                  "mean = ", formatC(sum_df$mean, digits = 3), "\n",
                  "sd = ", formatC(sum_df$sd, digits = 3), "\n")) +
    geom_line() + 
    geom_hline(aes(yintercept = sum_df$mean)) + 
    ylab("") + xlab("") +
    geom_hline(aes(yintercept = sum_df$m1), linetype = 2) +
    geom_text(x = 8, y = sum_df$m1, label = "10%", vjust = -1, check_overlap = TRUE) +
    geom_hline(aes(yintercept = sum_df$m2), linetype = 2) +
    geom_text(x = 8, y = sum_df$m2, label = "10%", vjust = 2, check_overlap = TRUE) +
    theme_classic(base_size = 12) +
    theme(plot.title = element_text(hjust = 0.5))

  return(g)
}

plot_list <- names(X1)[-1] %>% 
  map(~ generate_plot2(X1, "Point", .x))

#>     mean       sd     m1     m2
#> 1 554.75 26.15817 555.75 553.75
#>   mean      sd m1 m2
#> 1   48 6.78233 49 47
#>    mean       sd    m1    m2
#> 1 50.75 5.737305 51.75 49.75
#>    mean       sd    m1    m2
#> 1 23.75 4.349329 24.75 22.75

plot_list[[1]]

plot_list[[2]]

# bonus: combine all plots
library(cowplot)
plot_grid(plotlist = plot_list, 
          labels = 'AUTO',
          nrow = 2,
          align = 'hv',
          axis = 'tblr')

Created on 2019-03-16 by the reprex package (v0.2.1.9000)

Tung
  • 26,371
  • 7
  • 91
  • 115
  • Tidy evaluation resources: https://maraaverick.rbind.io/2017/08/tidyeval-resource-roundup/ – Tung Mar 16 '19 at 08:40
  • 1
    Thank you for taking the time to help me. I tried to run it and it gave me an error, unfortunately : Error in is.data.frame(x) : (list) object cannot be coerced to type 'double' In addition: Warning message: In mean.default(acq[, current_col]) : – Yria Mar 16 '19 at 08:43
  • and a message translated, from after the colon: The arguments are neither numeric nor logical. Returns NA value – Yria Mar 16 '19 at 08:43
  • I will look more into the tidy approach it looks more practical, thank you for the tip @Tung – Yria Mar 16 '19 at 09:20
  • I have one last question, if you don't mind. How can I generate all the plots in one pdf in the first code? – Yria Mar 16 '19 at 11:11
  • @Yria: you can combine all plots too https://stackoverflow.com/a/50930640/ – Tung Mar 16 '19 at 16:35