sayile firahs
sayile firahs

Reputation: 125

Error in m == q : R comparison (1) is possible only for atomic and list types

The whole function which i need to convert the for loop in to apply for optimization

plans_achievements <- function(pa_m,pa_q){
             if(nrow(pa_m)==0 & nrow(pa_q==0)){
                df = data.frame(a = c(""), b = c("No Data Available"))
                colnames(df)=""
              }else{
                pa_m= pa_m%>% select(inc,month_year,Plans,Achievements,quarter_year)
                colnames(pa_mon)[2] = "Period"
        
        pa_q= pa_q%>% select(inc,quarter_year,Plans,Achievements)
        colnames(pa_qtr)[2] = "Period"
        
        df = data.frame(inc=c(""),Period=c(""),Plans=c(""),Achievements=c(""))
        
        for (q in unique(pa_q$Period)){
          df1 = pa_q[pa_q$Period==q,]
          df1$Period = paste0("<span style=\"color:#288D55\">",df1$Period,"</span>")
          df1$Plans = paste0("<span style=\"color:#288D55\">",df1$Plans,"</span>")
          df1$Achievements = paste0("<span style=\"color:#288D55\">",df1$Achievements,"</span>")
          df = rbind(df,df1)
          for (m in unique(pa_m$quarter_year)){
            if(m==q){
              df2 = pa_m[pa_m$quarter_year==q,][-5]
              df = rbind(df,df2)
            }
          }
        }
        df = df[-1,]
      }
        return(df)
        }

The apply which i tried

my_fun <- function(q){
      df1 = pa_qtr[pa_qtr$Period==q,]
      df1$Period = paste0("<span style=\"color:#288D55\">",df1$Period,"</span>")
      df1$Plans = paste0("<span style=\"color:#288D55\">",df1$Plans,"</span>")
      df1$Achievements = paste0("<span style=\"color:#288D55\">",df1$Achievements,"</span>")
      df = rbind(df,df1)


    }
    df = do.call(rbind,lapply(unique(pa_qtr$Period), my_fun))
    
    my_fun2 <- function(m,my_fun){
      if (m == q) {
        df2 = pa_mon[pa_mon$qtr_yr == q, ][-5]
        df = rbind(df,df2)
      }
    }
    df = do.call(cbind,lapply(unique(pa_mon$qtr_yr), my_fun2))

DT::datatable(plans_achievements(pa_m[pa_m$inc=="vate",],pa_q[pa_q$inc=="vate",]), rownames = F,escape = FALSE,selection=list(mode="single",target="row"),options = list(pageLength = 50,scrollX = TRUE,dom = 'tp',ordering=F,columnDefs = list(list(visible=FALSE, targets=c(0)),list(className = 'dt-left', targets = '_all'))))

current output excepted output

Upvotes: 0

Views: 3272

Answers (1)

jpiversen
jpiversen

Reputation: 3222

Why you get the error comparison is possible only for atomic and list types

I will answer your original question first:

You get the error because you haven't defined q as a variable inside the function my_fun2. Since you haven't defined this variable, R will look for it in the global environment. There R will find the function q() (used to quit R). So you get the error message comparison (1) is possible only for atomic and list types because R thinks you are trying to compare a number m with the function q.

Here is a small example to make it easy to see:

# Run this in a clean environment

m <- 1

m == b # Understandable error message - "b" is not found
m == q # Your error - because R thinks you are comparing m to a function

You fix this error by making sure that q is defined inside your function. Either by creating it inside the function, or by supplying it as an input argument.

A possible solution for your problem

As I understand your code, you want to format, merge and sort the values in pa_q and pa_m, to display them in a html table.

Under is a possible solution, using tidyverse and vectorized operations, rather than a loop or apply functions. Vectorized functions are typically your fastest option in R, as I know you want to optimize your code.

library(dplyr)


plans_achievements <- function(pa_m, pa_q) {
  
  # I've modified the logic a bit: there is no need to wrap the full function in
  # an else statement, since we can return early if the data has no rows
  if (nrow(pa_m) == 0 && nrow(pa_q == 0)) {
    df = data.frame(a = c(""), b = c("No Data Available"))
    colnames(df) = ""
    
    return(df)
    
  }
  
  pa_q <- 
    pa_q %>% 
    # Select and rename the columns vi need
    select(inc, Period = quarter_year, Plans, Achievements, date) %>% 
    # Format the values
    mutate(
      Period = paste0("<span style=\"color:#288D55\">", Period,"</span>"),
      Plans = paste0("<span style=\"color:#288D55\">", Plans,"</span>"),
      Achievements = paste0("<span style=\"color:#288D55\">", Achievements,"</span>")
    )
  
  pa_m <- 
    pa_m %>% 
    # Select and rename the columns we need
    select(inc, Period = month_year, Plans, Achievements, date) #%>% 
  
  # Combine the datasets
  bind_rows(
    pa_q, 
    pa_m
  ) %>% 
    # Make sure that R understand date as a date value
    mutate(
      date = lubridate::dmy(date)
    ) %>% 
    # Sort by date
    arrange(desc(date)) %>% 
    # Remove columns we do not need
    select(-date, -inc)
  
}


DT::datatable(
  plans_achievements(
    pa_m[pa_m$inc=="vate",],
    pa_q[pa_q$inc=="vate",]
  ), 
  rownames = FALSE,
  escape = FALSE,
  selection = list(mode = "single", target = "row"),
  options = list(
    pageLength = 50,
    scrollX = TRUE,
    dom = 'tp',
    ordering = FALSE,
    columnDefs = list(
      list(className = 'dt-left', targets = '_all')
    )
  )
)

Hopefully this solves your problem.

Upvotes: 1

Related Questions