Search code examples
rshinyverbatim

r shiny make shiny print messages to user interface


I have a simple shiny app. First, I generated 2 csv files in my working directory:

write.csv(data.frame(a = 1:4, b = 2:5), "x.csv", row.names = F)
write.csv(data.frame(a = 1:4, c = 11:14), "y.csv", row.names = F)

In my app, I want the user to:

  1. read in 2 files (x.csv and y.csv) and...
  2. Click on the button 'Run'!
  3. After that I want server.R to write out 2 csv files - but also to print out certain messages for the user to see.

My code below works, but currently the messages for the user look very ugly and each is sitting on a dull gray background. Two questions:

  1. Is my method the only method to print messages for the user? Or maybe there is a more elegant one?

  2. How could I modify the gray background, font size, color, etc?

Thank you so much!

library(shiny)
library(shinyjs)

# ui code:

ui <- fluidPage(

  useShinyjs(),
  br(),
  # User should upload file x.csv here:
  fileInput("file_x", label = h5("Upload file 'x.csv'!")),
  br(),
  # User should upload file y.csv here:
  fileInput("file_y", label = h5("Upload file 'y.csv'!")),
  br(),
  # Users clicks the button:
  actionButton("do_it", "Run!"),
  br(),
  hidden(p("First, please upload one of the 2 files above!",
           id = "p_nofiles",
           style = "font-weight:bold;color:red;")),
  br(),
  verbatimTextOutput("message_1"),
  br(),
  verbatimTextOutput("message_2"),
  br(),
  verbatimTextOutput("message_3")

)

# server code:

server <- function(input, output, session) {

  observeEvent(input$do_it, {

    # If there file_x input is NULL, show the message in p_nofile
    if (is.null(input$file_x) | is.null(input$file_y)) {
      shinyjs::show("p_nofiles")
    } else {
      # if both files are selected, hide the p_nofiles message
      shinyjs::hide("p_nofiles")

      # Check my button's value:
      output$print_action <- renderPrint({input$do_it})

      # Read in file x_csv:
      infileX <- input$file_x
      if (is.null(infileX)) {  
        return(NULL)     
        }
      x <- read.csv(infileX$datapath)

      # Read in file y_csv:
      infileY <- input$file_y
      if (is.null(infileY)) {  
        return(NULL)     
      }
      y <- read.csv(infileY$datapath)

      #-------------------------------------------------------------------------------------------
      # MESSAGES I WANT THE USER TO SEE:

      # MESSAGE 1 - always there: What names do x and y have in common?
      mes1 <- paste0("x and y have these columns in common: ", 
                     intersect(names(x), names(y)), "\n")
      output$message_1 <- renderText({mes1})

      # MESSAGE 2 - with 2 alternative texts: Do x and y have the same number of rows?
      if (nrow(x) == nrow(y)) { 
        mes2 <- "x and y have the same number of rows!\n"
      } else {
          mes2 <- "x has a different number of rows than y\n"
      }
      output$message_2 <- renderText({mes2})

      # MESSAGE 3 - to be printed only under one condition:
      # Do x and y have a different number of columns? Print only it's different, otherwise - nothing
      if (ncol(x) != ncol(y)) { 
        mes3 <- "x and y do NOT have the same number of columns!\n"
        output$message_3 <- renderText({mes3})
      } else {output$message_3 <- renderText({NULL})}

      #-------------------------------------------------------------------------------------------
      # Writing out the same file x - but under a different name:

      filenameX <- paste0("x", input$do_it, ".csv")
      write.csv(x, file = filenameX, row.names = FALSE)

       # Writing out the same file y - but under a different name:
      filenameY <- paste0("y", input$do_it, ".csv")
      write.csv(y, file = filenameY, row.names = FALSE)
    }
  })
}

shinyApp(ui, server)

Solution

  • I edited your code, try this. What you need to pay attention is the part that has showModal(...) in server.

    library(shiny)
    library(shinyjs)
    

    UI code:

    ui <- fluidPage(
    
      useShinyjs(),
      br(),
      # User should upload file x.csv here:
      fileInput("file_x", label = h5("Upload file 'x.csv'!")),
      br(),
      # User should upload file y.csv here:
      fileInput("file_y", label = h5("Upload file 'y.csv'!")),
      br(),
      # Users clicks the button:
      actionButton("do_it", "Run!"),
      br(),
      hidden(p("First, please upload one of the 2 files above!",
               id = "p_nofiles",
               style = "font-weight:bold;color:red;"))
      # br(),
      # verbatimTextOutput("message_1"),
      # br(),
      # verbatimTextOutput("message_2"),
      # br(),
      # verbatimTextOutput("message_3")
    
    )
    

    Server code:

    server <- function(input, output, session) {
    
    observeEvent(input$do_it, {
    
    # If there file_x input is NULL, show the message in p_nofile
    if (is.null(input$file_x) | is.null(input$file_y)) {
      shinyjs::show("p_nofiles")
    } else {
      # if both files are selected, hide the p_nofiles message
      shinyjs::hide("p_nofiles")
    
      # Check my button's value:
      output$print_action <- renderPrint({input$do_it})
    
      # Read in file x_csv:
      infileX <- input$file_x
      if (is.null(infileX)) {
        return(NULL)
        }
      x <- read.csv(infileX$datapath)
    
      # Read in file y_csv:
      infileY <- input$file_y
      if (is.null(infileY)) {
        return(NULL)
      }
      y <- read.csv(infileY$datapath)
    
      #-------------------------------------------------------------------------------------------
      # MESSAGES I WANT THE USER TO SEE:
    
      # MESSAGE 1 - always there: What names do x and y have in common?
      mes1 <- paste0("x and y have these columns in common: ",
                     intersect(names(x), names(y)), "\n")
      # output$message_1 <- renderText({mes1})
    
    
      # MESSAGE 2 - with 2 alternative texts: Do x and y have the same number of rows?
      if (nrow(x) == nrow(y)) {
        mes2 <- "x and y have the same number of rows!\n"
      } else {
          mes2 <- "x has a different number of rows than y\n"
      }
      # output$message_2 <- renderText({mes2})
    
      # MESSAGE 3 - to be printed only under one condition:
      # Do x and y have a different number of columns? Print only it's different, otherwise - nothing
      if (ncol(x) != ncol(y)) {
        mes3 <- "x and y do NOT have the same number of columns!\n"
        # output$message_3 <- renderText({mes3})
      } else {mes3 <- renderText({NULL})}
    
      showModal(modalDialog(
        title = "Mensagens to User",
        "More Text",
        mes1,
        HTML("<br />"),
        mes2,
        HTML("<br />"),
        mes3,
        easyClose = TRUE,
        footer = "Footer"
        ))
    
      #-------------------------------------------------------------------------------------------
      # Writing out the same file x - but under a different name:
    
      filenameX <- paste0("x", input$do_it, ".csv")
      write.csv(x, file = filenameX, row.names = FALSE)
    
       # Writing out the same file y - but under a different name:
      filenameY <- paste0("y", input$do_it, ".csv")
      write.csv(y, file = filenameY, row.names = FALSE)
    }
      })
    }
    
    shinyApp(ui, server)