How to write a function for Median to use for Ggplot graph adaptable to different items from a dataset in R

Viewed 61

I need to create the same graph for different variables of my dataset. My dataset looks like:

    df5 <-  structure(list(P54a = c(20, 4, 3, 5, NA, 9, 18, 18, NA, 4, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, 17, 13, NA, NA, NA, NA), P79 = c(25, 
20, 12, NA, NA, 13, NA, NA, NA, 25, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 
NA, NA, 15, NA, 1, NA, NA), center = c(203, 203, 203, 203, 108, 
108, 206, 206, 206, 206, 116, 116, 116, 116, 116, 116, 116, 116, 
116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 
116, 116, 713, 713, 713, 718, 718, 718, 718)), row.names = c(NA, 
40L), class = "data.frame")

I wrote the code for one variable and it seems to work fine. To avoid copying the same code several times I wanted to create a function that would allow me to use the function by just defining the variable of interest and the center. The code for the "individual item" P54a and for the center 206 looks like this: (center 713 would be the center which I'm comparing with center 206, the "reference center")

a<-df5 %>% 
    group_by(center) %>%
    summarise(P54a = median(P54a, na.rm=T)) 
  a$center=factor(a$center, levels = a$center)
  a %>%
    mutate(center = fct_reorder(center,P54a)) ->a
  
  b<-a$P54a[which(a$center==713)] #pick the value of the reference center
  a1 <- a %>% 
    group_by(center) %>% 
    mutate(my_label = ifelse(center %in% c("206","713"),
                             paste(center,P54a, sep = ":"), NA)) %>% 
    ungroup()
  
  d <- ggplot(data=a1,aes(x=center,label=center,y=P54a,
                          fill=factor(ifelse(center=="206","target",ifelse(center== "713","Reference","all"))))) +
    geom_bar(stat= "identity") +
    scale_fill_manual(name = "center", values=c("cadetblue","gold", "orange")) +
    xlab("TitelX") +
    ylab("Median") +
    ggtitle("Titelgraph") +
    #d<- d+ theme(axis.text.x=element_blank(), axis.ticks.x=element_blank(),legend.position = "none") 
    geom_hline(aes(yintercept= b), data= filter(a1, center== 713), color="black", linetype="dashed") + ylim(0, 20)+
    #geom_text_repel(aes(label = my_label),size= 3, box.padding = 0.5 , max.overlaps = Inf)
    theme(axis.text.x=element_blank(), axis.ticks.x=element_blank(),legend.position = "none") + 
    geom_label(label=a1$my_label, vjust = -0.1)
   d

The try that didn't worked:

 bar_plot <- function(itemNo, # would be the defined item
                         df = df5, # the full dataset 
                         target= target_center (in my example the 206)
    ){
    
      df1 <- subset(df5, select= itemNo)
      df2 <- subset(df5, select= center)# the original dataset has other variables that's why I would here select the center item.
      df6 <- cbind(df1, df2)
    
    
    a<-df6 %>% group_by(center) %>% summarise(med_x = median(itemNo, na.rm=T)) a$center=factor(a$center, levels = a$center) a %>% mutate(center = fct_reorder(center,med_x)) ->a
    
    b<-a$itemNo[which(a$center==713)] #pick the value of the reference center 
    a1 <- a %>% group_by(center) %>% mutate(my_label = ifelse(center %in% c("target","713"), paste(center,itemNo, sep = ":"), NA)) %>% ungroup()
    
    d <- ggplot(data=a1,aes(x=center,label=center,y=itemNo, fill=factor(ifelse(center=="target","target",ifelse(center== "713","Reference","all"))))) +
 geom_bar(stat= "identity") + scale_fill_manual(name = "center", values=c("cadetblue","gold", "orange")) + xlab("TitelX") + 
ylab("Median") + ggtitle("Titelgraph") +  geom_hline(aes(yintercept= b), data= filter(a1, X0== 713), color="black", linetype="dashed") + ylim(0, 20)+ 
theme(axis.text.x=element_blank(), axis.ticks.x=element_blank(),legend.position = "none") + geom_label(label=a1$my_label, vjust = -0.1) 
    return(d)

The first problem starts with the median, it doesn't take the values of the defined variable/item but the item Name and inserts as the median the name of the variable. It's the first time I'm writing functions.., I tried to find the solution in previous questions/answers but it didn't worked.. for example using for the median :

median = numeric(0)
  for( i in 1:ncol(df5)){
    median[i] = median(df5[,i], na.rm=TRUE)
  }

Any help is very welcome. Many thanks

1 Answers

The error you're getting is understandable because you are calling the column name inside the function. But there are two more things you should keep in mind IMO:

  1. When you're wrapping down your code by a function, always try to run it line by line inside the function with the function parameter values already defined in the global environment. This will enable you to spot the mistake easily. Like I did here. I took your code which was working and then wrapped it with necessary changes.

  2. The way you have defined the functional input parameters and then went ahead to use them inside the function is wrong. Have a look at my code, you'll understand the difference.

The function:

bar_plot <- function(itemNo, df5, center){
  
  df1 <- subset(df5, select= itemNo)
  df2 <- subset(df5, select= center)
  df6 <- cbind(df1, df2)
  
  a<-df6 %>% 
    group_by(center) %>%
    summarise(itemNo = median(!! sym(itemNo), na.rm=T)) 
  a$center=factor(a$center, levels = a$center)
  a %>%
    mutate(center = fct_reorder(center,itemNo)) ->a
  
  b<-a$itemNo[which(a$center==713)] #pick the value of the reference center
  a1 <- a %>% 
    group_by(center) %>% 
    mutate(my_label = ifelse(center %in% c("206","713"),
                             paste(center,itemNo, sep = ":"), NA)) %>% 
    ungroup()
  
  d <- ggplot(data=a1,aes(x=center,label=center,y=itemNo,
                          fill=factor(ifelse(center=="206","target",ifelse(center== "713","Reference","all"))))) +
    geom_bar(stat= "identity") +
    scale_fill_manual(name = "center", values=c("cadetblue","gold", "orange")) +
    xlab("TitelX") +
    ylab("Median") +
    ggtitle("Titelgraph") +
    #d<- d+ theme(axis.text.x=element_blank(), axis.ticks.x=element_blank(),legend.position = "none") 
    geom_hline(aes(yintercept= b), data= filter(a1, center== 713), color="black", linetype="dashed") + ylim(0, 20)+
    #geom_text_repel(aes(label = my_label),size= 3, box.padding = 0.5 , max.overlaps = Inf)
    theme(axis.text.x=element_blank(), axis.ticks.x=element_blank(),legend.position = "none") + 
    geom_label(label=a1$my_label, vjust = -0.1)
  d
  
}

Now call it and see the output:

bar_plot('P54a', df5, 206)

1st output

Another one:

bar_plot('P79', df5, 206)

2nd Output

Let me know if you have any queries.

Related