Create new objects in a function based on inputs

I'm trying to write a function that will create a ggplot that has components all based on a single input. I have a data frame with race, results on three assessments (reading, writing, math) plus the confidence interval for each result. I want to create a function that will create the same plot based on Read, Write or Math.

Example:

library(tidyverse)
dat <- data.frame (Race = c("White", "Black", "Inidigenous"),
                  Read_perc = c (0.756, 0.592, 0.548),
                  Read_low_ci = c (0.742, 0.498, 0.467),
                  Read_high_ci = c(0.769, 0.679, 0.628),
                  Write_perc = c (0.717, 0.625, 0.497),
                  Write_low_ci = c (0.703, 0.532, 0.416),
                  Write_high_ci = c (0.731, 0.710, 0.578))

my_plot_function <- function (df, var){
  var <- enquo(var)
  df %>% 
    ggplot (aes (x = reorder (Race, !! var), y = !! var)) +
    geom_col () +
    coord_flip () +
    geom_text (aes (label = scales::percent(!! var, accuracy = 1)),
               y = 0.05,
               colour = "white")
  
}

my_plot_function(dat, Read_perc)

Works great, but how do I modify it so that my_plot_function (dat, Read) will work? Normally I would write:

var <- "Read"
var_perc <- paste0(var, "_perc")
var_low_CI <- paste0(var, "_low_ci")
var_high_CI <- paste0(var, "_high_ci")

For example, I would like the function to read something like:

my_plot_function <- function (df, var){

var <- enquo (var)
var_low_ci <- paste0 (var, "_low_ci")
var_high_ci <- paste0 (var, "_high_ci")

df %>% 
    ggplot (aes (x = reorder (Race, !! var), y = !! var)) +
    geom_col () +
    coord_flip () +
    geom_text (aes (label = scales::percent(!! var, accuracy = 1)),
               y = 0.05,
               colour = "white") +
       geom_errorbar(aes(ymin = var_low_ci,
                         ymax = var_high_ci),
                         colour = "black")

Hi @GregRousell,
When I read your question I saw a problem employing a complex user-defined function that could be made a lot simpler if the dataset was rearranged:

library(tidyverse)
dat <- data.frame (Race = c("White", "Black", "Inidigenous"),
                  Read_perc = c (0.756, 0.592, 0.548),
                  Read_low_ci = c (0.742, 0.498, 0.467),
                  Read_high_ci = c(0.769, 0.679, 0.628),
                  Write_perc = c (0.717, 0.625, 0.497),
                  Write_low_ci = c (0.703, 0.532, 0.416),
                  Write_high_ci = c (0.731, 0.710, 0.578))

pivot_longer(dat, cols=c(2:7)) -> long.df

long.df %>% 
  separate(., col=name, into=c("Subject","Stat")) -> long2.df

long2.df

pivot_wider(long2.df, id_cols=c(Race,Subject), names_from=Stat) -> wide.df

ggplot(wide.df, aes(x= reorder(Race, perc), y = perc)) +
  geom_col () +
  coord_flip () +
  facet_grid(~ Subject)

I couldn't get the tidyr bits nicely combined into one but you get the idea.
Of course, maybe you were writing your function as a proof-of-concept, in which case, this reply will not help!

HTH

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

I tried that approach as well but the data set is much larger and complex than the example. I was able to get am answer using the sym function. https://stackoverflow.com/questions/61373048/how-do-i-create-a-new-object-in-an-r-function-that-i-can-use-within-the-functio/61373131#61373131

1 Like