0

I have a column 'R/Y/G' that should contain three colors Green, Yellow or Red based on values from three different columns R, Y and G. The condition is that if the value of column 'R' is greater than 2.5 million, the color of the corresponding cell in 'R/Y/G' is Red. If the value of column 'Y' is between 2 and 2.5 mil, the color of the corresponding cell in 'R/Y/G' is Yellow. If the value of column 'G' is less than 2 mil, the color of the corresponding cell in 'R/Y/G' is Green. Here the condition :

d9$tcolor <- ifelse(d9$R > 2500000, 2,
                        ifelse(d9$Y > 2000000 & d9$Y <= 2500000, 1,
                               ifelse(d9$G <= 2000000, 0)))

dt_d9=datatable(isolate(d9), editable = 'cell', rownames = FALSE, extensions = 'Buttons', options = list(dom = 'Bfrtip', buttons = I('colvis'))) %>% formatStyle(
    'R/Y/G', 'tcolor',
    backgroundColor = styleEqual(c(0,1,2), c('green', 'yellow', 'red')),fontWeight = 'bold'
  )

tcolor is a column I've created to track the three columns ('R', 'Y' and 'G') and the color for column 'R/Y/G' will be dependent on tcolor based on what values I input in 'R', 'Y' and 'G'

Here's where it is implemented in actual code :

cmp_data1 <- dbGetQuery(qr,sql)

saveRDS(cmp_data1, 'q1.rds')

dt_output = function(title, id) {
  fluidRow(column(
    12, h1(paste0(title)),
    hr(), DTOutput(id)
  ))
}

render_dt = function(data, editable = 'cell', server = TRUE, ...) {
  renderDT(data,selection = 'none', server = server, editable = editable, ...)
}

ui = fluidPage(
  downloadButton("mcp_csv", "Download as CSV", class="but"),
  
  dt_output('Report', 'x9')
)

server = function(input, output, session) {
  if(!file.exists("cm.rds")){
    d9 = cmp_data1
    d9['R/Y/G'] <- NA
    d9['R'] <- NA
    d9['Y'] <- NA
    d9['G'] <- NA
    d9['tcolor'] <- NA
  }
  else{
    cmp <- readRDS("cm.rds")
    d9 = cbind(cmp_data1, cmp[,(ncol(cmp)-4):ncol(cmp)])
  }
  
  rv <- reactiveValues()
  observe({
    rv$d9 <- d9
  })
  
  dt_d9=datatable(isolate(d9), editable = 'cell', rownames = FALSE, extensions = 'Buttons', options = list(dom = 'Bfrtip', buttons = I('colvis'))) %>% formatStyle(
    'R/Y/G', 'tcolor',
    backgroundColor = styleEqual(c(0,1,2), c('green', 'yellow', 'red')),fontWeight = 'bold'
  )
  
  output$x9 = render_dt(dt_d9)
  
  proxy = dataTableProxy('x9')
  observe({
    DT::replaceData(proxy, rv$d9, rownames = FALSE, resetPaging = FALSE)
  })
  
  observeEvent(input$x9_cell_edit, {
    rv$d9 <<- editData(rv$d9, input$x9_cell_edit, 'x9', rownames = FALSE)
    d9 <- rv$d9
    d9$tcolor <- ifelse(d9$R > 2500000, 2,
                        ifelse(d9$Y > 2000000 & d9$Y <= 2500000, 1,
                               ifelse(d9$G <= 2000000, 0)))
    rv$d9 <<- d9
    saveRDS(d9, 'cm.rds')
    
  })

But this doesn't seem to work. The colors don't show up.

retrx22
  • 61
  • 1
  • 9

1 Answers1

1

The created empty columns get character type instead of numeric, so you must create the empty columns with numeric type like this:

  d9['R/Y/G'] <- numeric()
  d9['R'] <- numeric()
  d9['Y'] <- numeric()
  d9['G'] <- numeric()
  d9['tcolor'] <- numeric()

Learn how to debug Shiny apps by inserting breakpoints to check the type of your objects/columns.

By the way, you don't handle the case when d9$G > 2000000.

Edit: if you need some default color to be displayed before the user enters any value, you should set some default value for the tcolor column, e.g. for green:

  d9['tcolor'] <- 1

To get your desired behavior of cascading conditions and not be bothered by NA values (when no value is entered in a column), you can use the case_when() function from the dplyrpackage (see this post):

d9$tcolor <- dplyr::case_when(d9$R > 2500000 ~ 2,
                      d9$Y > 2000000 & d9$Y <= 2500000 ~ 0,
                      d9$G < 2000000 ~ 1) 
julien.leroux5
  • 969
  • 7
  • 17
  • By default, the 'R/Y/G' should be green even if no value is entered. Also what's happening is after editing only the Red color shows up while editing the 'R' column. Yellow and Green don't show up.while editing the 'Y' and 'G' columns. I don't handle d9$G>2000000 as column 'G' is not supposed to have a value greater than 2 mil – retrx22 Sep 05 '21 at 12:22
  • Your series of if statements first checks the value in the `d9$R` column before testing values in the `d9$Y` column, and finally in the `d9$G` column. So yes you need some values entered in the `d9$R` column before yellow or green can be displayed. If you want a different behavior you need to rethink your test logic. And *column 'G' is not supposed to have a value greater than 2 mil* does not mean that the user will not try to enter such high value (which breaks the app). – julien.leroux5 Sep 05 '21 at 20:09
  • Even after setting a default value for green, once I make an edit, all of them disappear. I tried making several edits for 'Y' and 'G' after editing 'R', but only Red shows up while Green and Yellow don't. Things were working as expected before I implemented the merge thing(columns from query + columns from R on the fly) here : https://stackoverflow.com/questions/68834742/change-color-of-cells-as-soon-as-datatable-cell-value-is-edited-r-shiny/68868445#68868445 – retrx22 Sep 06 '21 at 04:14
  • Yes of course, again this is due to your if statements. Try to input R = 2000000, Y = 2100000 and G = 1 and you'll get some green. Try R = 2000000, Y = 1 and G = 1 to get some yellow. You never provided your test data ("cmp.rds") in the previous version so we cannot guess why and how it worked "as expected" before. I had to create one myself containing some RGB values and it works exactly as this new version. – julien.leroux5 Sep 06 '21 at 06:37
  • Earlier, by default every cell of 'R/Y/G' was green. I'll give some examples: Suppose I enter value = 3.2(>2.5 mil) mil in 'R' column and no other values for 'Y' or 'G'. Then 'R/Y/G' becomes Red. Suppose I enter value = 2.3 mil (between 2 and 2.5 mil) in 'Y' column and no other values for 'R' or 'G'. Then 'R/Y/G' becomes Yellow. Suppose 'R' value is 2.7 mil and 'Y' value is 2.1 mil. So 'R/Y/G' is Red. If there is no value for 'R' or 'Y' or 'G', then 'R/Y/G' is Green. – retrx22 Sep 06 '21 at 06:58
  • 1
    It's difficult to get the desired result using nested `ifelse` by keeping the possibility to have either values or NA (i.e. no value entered) in each column. A good alternative to `ifelse` statements is the `case_when()` function from the `dplyr` package to sort of ignore NA values. See my edit. – julien.leroux5 Sep 06 '21 at 21:32
  • That worked great! Thanks a lot. I'm relatively new to R, so I really appreciate your patience and clarifications. – retrx22 Sep 06 '21 at 22:10