3

I have some requests for my app.

{1} After readjusting the mainPanel, esquisserUI filters are not popping up anymore. Here is the working example which I followed https://dreamrs.github.io/esquisse/articles/shiny-usage.html In addition, I also looked at this GitHub issue, however it was for disabling the filters: https://github.com/dreamRs/esquisse/issues/71 enter image description here

And final request regarding general information:

{2} what does server = FALSE will do for huge datasets? (https://rstudio.github.io/DT/server.html) DT recommends to leave it as default to TRUE state, however if I do that, I don't get the full data upon download. I only get the data in the current page. Are there problems you foresee?

Thank you, here is a reproducible example.

library(shiny)
library(shinyjs)
library(shinyWidgets)
library(esquisse)
library(shinythemes)
library(xlsx)
library(DT)

# Credit: @Iz100 helped me a lot with UI.

ui <- fluidPage(
  
  theme = shinytheme("simplex"),
  
  
  useShinyjs(),
  
  # Create Right Side Text
  navbarPage( 
    
    title= div(HTML("G<em>T</em>")),
    
    tabPanel("Data Set Info",
             
             materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
                            value = TRUE, status = "warning"),
             sidebarLayout(
               # radio/action buttons
               sidebarPanel(
                 
                 id = "Sidebar",
                 
                 prettyRadioButtons(
                   inputId = "controller",
                   label = "Choose:", 
                   choices = c("About"= 1,
                               "iris"= 2,
                               "mtcars" = 3),
                   icon= icon("check"),
                   selected = 1,
                   status = "success",
                   animation="smooth"
                 ),
                 
                 br(),
                 br(),
                 a(actionButton(inputId = "admin_email", label = "Contact Admin", 
                                icon = icon("envelope", lib = "font-awesome")),
                   href="mailto:my_awesome_email_address.com")
               ),
               
               #panel where output is shown from server
               mainPanel(
                 id = "main_panel",
                 
                 tabsetPanel(
                   id = "hidden_tabs",
                   type = "hidden",
                   tabPanelBody(
                     "panel1", "navigation"
                   ),
                   
                   tabPanelBody(
                     "panel2", 
                     tabsetPanel(
                       tabPanel("Data", DT::DTOutput('panel1_data')),
                       tabPanel("Summary", verbatimTextOutput("panel1_sum")),
                       tabPanel(
                         "Plot",
                         esquisserUI(
                           id = "esquisse2",
                           header = FALSE, 
                           choose_data = FALSE
                         )
                       )
                     )
                   ),
                   tabPanelBody(
                     "panel3",
                     tabsetPanel(
                       tabPanel("Data", DT::DTOutput('panel3_data')),
                       tabPanel("Summary", verbatimTextOutput("panel3_sum")),
                       tabPanel(
                         "Plot",
                         esquisserUI(
                           id = "esquisse3",
                           header = FALSE, 
                           choose_data = FALSE
                         )
                       )
                     )
                   )
                 )
               )
             )
    ) ,
    #resizes the navbar tabs/button
    tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;}')))
  )
)

server <- function(input, output, session) {
  
  # this event hides the side panel when toggled on/off
  observeEvent(input$toggleSidebar, {
    shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
    if(!isTRUE(input$toggleSidebar)) {
      shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
    } else {
      shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
    }
    
  })
  
  
  myModal <- function() {
    div(id = "Download_DATA",
        modalDialog(easyClose = TRUE,
                    title = "Alert!",
                    "Please remove all the filters if you want a full dataset.",
                    br(),
                    br(), 
                    downloadButton("download_excel","Download as XLSX")
        )
    )
  }
  
  
  # here we put all the data
  data_sets <- list(df1 = data.frame(), 
                    df2= iris, 
                    df3 = mtcars)
  
  # store current dataset in reactive so we can work with plot panels
  data_to_use <- reactiveValues(name = "df", data = data.frame())
  
  # modules only need to be called it once but individually for esquisse
  callModule(
    module = esquisserServer,
    id = "esquisse2",
    data = data_to_use
  )
  callModule(
    module = esquisserServer,
    id = "esquisse3",
    data = data_to_use
  )
  
  observeEvent(input$controller, {
    
    # skip first panel since it is used to display navigation
    updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
    
    # enswure value is avilable throught selected tabSet
    req(input$controller)
    
    # get current data and df name
    data_to_use$data <- data_sets[[as.numeric(input$controller)]]
    data_to_use$name <- names(data_sets[as.numeric(input$controller)])
    
    # update table and sum
    output[[paste0('panel',  input$controller, '_data')]] <- DT::renderDT(server = FALSE, {
      DT::datatable(data_to_use$data,
                    filter = 'top', 
                    extensions = 'Buttons',
                    options = list(scrollY = 600,
                                   scrollX = TRUE,
                                   dom = '<"float-left"l><"float-right"f>rt<"row"<"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>',
                                   lengthMenu=  list(c(10, 25, 50, -1), 
                                                     c('10', '25', '50','All')),
                                   buttons = list(
                                     list(extend = "collection", text = "Download", 
                                          filename = "data_excel",
                                          exportOptions = list(
                                            modifier = list(page = "all")
                                          ),
                                          action = DT::JS("function ( e, dt, node, config ) {
                                    Shiny.setInputValue('Download_DATA', true, {priority: 'event'});}"
                                          )
                                     )
                                   ),
                                   scrollCollapse= TRUE,
                                   lengthChange = TRUE, 
                                   widthChange= TRUE,
                                   rownames = TRUE))})
    
    output[[paste0('panel',  input$controller, '_sum')]] <- renderPrint(summary(data_to_use$data))
    
  })
  
  # observes if download is clicked
  observeEvent(input$Download_DATA, {
    showModal(myModal())
  })
  
  # writes to an excel file
  output$download_excel <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".xlsx", sep="")
    },
    content = function(file) {
      write.xlsx(data_to_use$data, file, row.names = FALSE)
    }
  )
  
  
}

#runs the app
shinyApp(ui= ui, server= server)


AOE_player
  • 536
  • 2
  • 11
  • 2
    Have you reference more about options yet? This website holds extensive configs. related to DT: https://datatables.net/reference/option/ – WolfgangBagdanow Apr 04 '21 at 04:00
  • @WolfgangBagdanow thanks for the information...yes that's the site where I got `dom` related stuff. But I can't read most of it due to poor knowledge about jQuery. They also have no explanation on how to move the button :( – AOE_player Apr 04 '21 at 04:05
  • 2
    @WolfgangBagdanow, thank you, I played around with the jQuery and found out `dom= '<"float-left"l><"float-right"f>rt<"row"<"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>'` solves my problem. Thank you! – AOE_player Apr 04 '21 at 20:41
  • I have edited the question too since I no longer need help with relocating Button. – AOE_player Apr 04 '21 at 20:45
  • No problem! Glad you were able to find a solution to one of your issues. – WolfgangBagdanow Apr 07 '21 at 02:09

1 Answers1

0

1. I checked the HTML of esquisserUI, they give all dropdowns the same IDs if you use multiple esquisserUI. This is a big NO in HTML development and will cause a lot of issues. They call it a module, but they didn't follow Shiny module guidelines where to use NS() for all UI IDs. The easy proof is try this below. Then uncomment the second set of esquisserUI and esquisserServer and try again. You will find the dropdown no longer works.

library(esquisse)
ui <- fluidPage(
    esquisserUI(
        id = "esquisse1",
        header = FALSE, 
        choose_data = FALSE
    )#,
    # esquisserUI(
    #     id = "esquisse2",
    #     header = FALSE,
    #     choose_data = FALSE
    # )
)

server <- function(input, output, session) {
    data_to_use <- reactiveValues(data = iris, name = "iris")
    callModule(
        module = esquisserServer,
        id = "esquisse1",
        data = data_to_use
    )
    # callModule(
    #     module = esquisserServer,
    #     id = "esquisse2",
    #     data = data_to_use
    # )
}

shinyApp(ui, server)

Currently there is no straight fix for this unless you ask them to fix it. We need to use a workaround:

I added a new tab to the main panel called "plot" which is the esquisserUI, and two buttons in the data panel so when you click on the button, it will jump you to the plot panel with the right data.

library(shiny)
library(shinyjs)
library(shinyWidgets)
library(esquisse)
library(shinythemes)
library(xlsx)
library(DT)

# Credit: @Iz100 helped me a lot with UI.
ns <- NS("myapp")
ui <- fluidPage(
    
    theme = shinytheme("simplex"),
    
    
    useShinyjs(),
    
    # Create Right Side Text
    navbarPage( 
        
        title= div(HTML("G<em>T</em>")),
        
        tabPanel("Data Set Info",
                 
                 materialSwitch(inputId = "toggleSidebar", label = "Toggle Panel: ",
                                value = TRUE, status = "warning"),
                 sidebarLayout(
                     # radio/action buttons
                     sidebarPanel(
                         
                         id = "Sidebar",
                         
                         prettyRadioButtons(
                             inputId = "controller",
                             label = "Choose:", 
                             choices = c("About"= 1,
                                         "iris"= 2,
                                         "mtcars" = 3,
                                         "plots" = 4),
                             icon= icon("check"),
                             selected = 1,
                             status = "success",
                             animation="smooth"
                         ),
                         
                         br(),
                         br(),
                         a(actionButton(inputId = "admin_email", label = "Contact Admin", 
                                        icon = icon("envelope", lib = "font-awesome")),
                           href="mailto:my_awesome_email_address.com")
                     ),
                     
                     #panel where output is shown from server
                     mainPanel(
                         id = "main_panel",
                         
                         tabsetPanel(
                             id = "hidden_tabs",
                             type = "hidden",
                             tabPanelBody(
                                 "panel1", "navigation"
                             ),
                             
                             tabPanelBody(
                                 "panel2", 
                                 tabsetPanel(
                                     tabPanel(
                                         "Data", DT::DTOutput('panel2_data'),
                                         actionButton("plot2", "Plot iris")
                                     ),
                                     tabPanel("Summary", verbatimTextOutput("panel2_sum"))
                                 )
                             ),
                             tabPanelBody(
                                 "panel3",
                                 tabsetPanel(
                                     tabPanel(
                                         "Data", DT::DTOutput('panel3_data'),
                                         actionButton("plot3", "Plot mtcars")
                                     ),
                                     tabPanel("Summary", verbatimTextOutput("panel3_sum"))
                                 )
                             ),
                             tabPanelBody(
                                 "panel4",
                                 esquisserUI(
                                     id = "esquisse",
                                     header = FALSE, 
                                     choose_data = FALSE
                                 )
                             )
                         )
                     )
                 )
        ),
        #resizes the navbar tabs/button
        tags$head(tags$style(HTML('.navbar-brand {width: 270px; font-size:35px; text-align:left;}')))
    )
)

server <- function(input, output, session) {
    
    # this event hides the side panel when toggled on/off
    observeEvent(input$toggleSidebar, {
        shinyjs::toggle(id = "Sidebar", condition = input$toggleSidebar)
        if(!isTRUE(input$toggleSidebar)) {
            shinyjs::runjs("$('#main_panel').removeClass('col-sm-8').addClass('col-sm-12')")
        } else {
            shinyjs::runjs("$('#main_panel').removeClass('col-sm-12').addClass('col-sm-8')")
        }
        
    })
    
    
    myModal <- function() {
        div(id = "Download_DATA",
            modalDialog(easyClose = TRUE,
                        title = "Alert!",
                        "Please remove all the filters if you want a full dataset.",
                        br(),
                        br(), 
                        downloadButton("download_excel","Download as XLSX")
            )
        )
    }
    
    
    # here we put all the data
    data_sets <- list(df1 = data.frame(), 
                      df2= iris, 
                      df3 = mtcars)
    
    # store current dataset in reactive so we can work with plot panels
    data_to_use <- reactiveValues(name = "df", data = data.frame())
    
    # modules only need to be called it once but individually for esquisse
    callModule(
        module = esquisserServer,
        id = "esquisse",
        data = data_to_use
    )
    # go to plot panel if plot button clicked
    observeEvent(c(input$plot2, input$plot3), {
        updatePrettyRadioButtons(session, "controller", selected = 4)
    }, ignoreInit = TRUE)
    
    observeEvent(input$controller, {
        
        # skip first panel since it is used to display navigation
        updateTabsetPanel(session, inputId= "hidden_tabs", selected = paste0("panel", input$controller))
        
        # enswure value is avilable throught selected tabSet
        # only render data if data panels are selected
        req(input$controller %in% 2:3)
        
        # get current data and df name
        data_to_use$data <- data_sets[[as.numeric(input$controller)]]
        data_to_use$name <- names(data_sets[as.numeric(input$controller)])
        
        # update table and sum
        output[[paste0('panel',  input$controller, '_data')]] <- DT::renderDT(server = FALSE, {
            DT::datatable(data_to_use$data,
                          filter = 'top', 
                          extensions = 'Buttons',
                          options = list(scrollY = 600,
                                         scrollX = TRUE,
                                         dom = '<"float-left"l><"float-right"f>rt<"row"<"col-sm-4"B><"col-sm-4"i><"col-sm-4"p>>',
                                         lengthMenu=  list(c(10, 25, 50, -1), 
                                                           c('10', '25', '50','All')),
                                         buttons = list(
                                             list(extend = "collection", text = "Download", 
                                                  filename = "data_excel",
                                                  exportOptions = list(
                                                      modifier = list(page = "all")
                                                  ),
                                                  action = DT::JS("function ( e, dt, node, config ) {
                                    Shiny.setInputValue('Download_DATA', true, {priority: 'event'});}"
                                                  )
                                             )
                                         ),
                                    scrollCollapse= TRUE,
                                    lengthChange = TRUE, 
                                    widthChange= TRUE,
                                    rownames = TRUE))})
        
        output[[paste0('panel',  input$controller, '_sum')]] <- renderPrint(summary(data_to_use$data))
        
    })
    
    # observes if download is clicked
    observeEvent(input$Download_DATA, {
        showModal(myModal())
    })
    
    # writes to an excel file
    output$download_excel <- downloadHandler(
        filename = function() {
            paste("data-", Sys.Date(), ".xlsx", sep="")
        },
        content = function(file) {
            write.xlsx(data_to_use$data, file, row.names = FALSE)
        }
    )
    
    
}

#runs the app
shinyApp(ui= ui, server= server)

2. So server = TRUE only sends a very small portion of the entire dataset to UI for large ones. When you scroll or jump pages, new data will be sent. This saves time and has better performance. If it is FALSE, all data will be sent at once. Imagine you need to load a 2GB table in your browser everytime you start the app, how slow will it be. For small datasets, you can leave it FALSE.

Updates It seems esquisse people fixed the bug. Install the develop version and then:

ui <- fluidPage(
    esquisse_ui(
        id = "esquisse1",
        header = FALSE
    ),
    esquisse_ui(
        id = "esquisse2",
        header = FALSE
    )
)

server <- function(input, output, session) {
    data_to_use <- reactiveValues(data = iris, name = "iris")
    esquisse_server(id = "esquisse1", data_rv = data_to_use)
    esquisse_server(id = "esquisse2", data_rv = data_to_use)
}

shinyApp(ui, server)
lz100
  • 6,990
  • 6
  • 29
  • Thank you @Iz100, I sent a tweet to them, they did acknowledge the bug. Anyhow, I appreciate your answer again, and your time you put in this question. Please wait until the bounty period is over so I can award the reps to you :) – AOE_player Apr 08 '21 at 00:14
  • I wonder if esquisse package works well with shinydashboard...that toggle is getting to be a big headache. I will play around. – AOE_player Apr 08 '21 at 01:15