Search code examples
rggplot2plotshinyshinyapps

Display the output of several plots on top of each other in Shiny App


I am making a Shiny App that generates a graph and in the application there is the option to modify this graph. In the mainPanel() I have 6 plotOutputs and I would like that each time that one of these 6 modifications is made the graph comes out the first one (above the previous one). Currently I get them in order as they are in mainPanel and at the top if I draw "tree" and "rotate" it leaves a space between the graphics as if "reroot" was missing. Photo as it appears now

For example, the first graph to be generated is "tree". If I make the modification "rotate", the graph should come out just above the other one (without leaving spaces). And if I then do "flip", this graph would come out on top of "rotate".

Is there any possibility to do it? Would it also be possible to show only 3 plots? That is to say, if there are already 3 graphs in the panel and I want to make a fourth modification, the graph that has been generated first (the last of the panel) will not be drawn.

ui <- fluidPage(
  
  # Sidebar layout with input and output definitions
  sidebarLayout(
    
    # Sidebar panel for inputs
    sidebarPanel(
      
      span(titlePanel("Shiny App"), style = "text-align: center"),
      
      p(span("Shiny application to facilitate the construction, editing and manipulation of phylogenetic trees."), style = "font-size: 16px; color: #00509D"), #9B9D9F
      br(), 
      
      radioButtons(inputId = "start",
                   label = "Select an option:", 
                   choices = c("Choose file .tre" = "file", 
                               "Search in PR2 database" = "PR2"),
                   selected = "Choose file .tre"), #FUNCIONA: selected = "file"
      
      conditionalPanel(
        condition = "input.start == 'file'",
        fileInput(inputId = "tre",
                  label = "Choose file:")
        ),
    
      conditionalPanel(
        condition = "input.start == 'PR2'",
        selectInput(inputId = "tax",
                    label = "Choose taxonomic group:",
                    choices = c("Domain", "Kingdom", "Phylum", "Class", "Order", "Family", "Genus", "Species"),
                    selected = "Order"),
        textInput(inputId = "clade",
                  label = "Group name:",
                  value = "Suessiales"),
        # Help
        helpText("You can run the example to build a phylogenetic tree 
               for the order Suessiales, unicellular organisms of the 
               superclass Dinoflagellata.")
      ),
      
      p("_____________________________"),
      checkboxInput(inputId = "root",
                    label = strong("Reroot")),
      
      numericInput(inputId = "val_root",
                   label = "Branch number:",
                   value = 87),
      
      checkboxInput(inputId = "rot",
                    label = strong("Rotate")),
      
      numericInput(inputId = "val_rot",
                   label = "Branch number:",
                   value = 87),
      
      checkboxInput(inputId = "flip",
                    label = strong("Flip")),
      
      numericInput(inputId = "val_f1",
                   label = "Node 1 number:",
                   value = 87),
      
      numericInput(inputId = "val_f2",
                   label = "Node 2 number:",
                   value = 72),
      
      p("_____________________________"),
      checkboxInput(inputId = "rename",
                    label = strong("Rename branches")),
      fileInput(inputId = "refile",
                label = "Choose file:")
      
    ),
    
    # Main panel for displaying outputs ----
    mainPanel(
      
      plotOutput("tree"),
      
      plotOutput("root"),

      plotOutput("rotate"),

      plotOutput("flip"),
      
      plotOutput("rename")
      
    )
  )
)

Solution

  • This is possible when you let the server render the order of the charts.

    The solution uses a reactive expression ChartOrder where it places the order of the charts. For every chart an observer handles the dependency to the input widgets and re-orders ChartOrder.

    The output$ListOfCharts renders the order accordingly.

    UsingChartOrder you can change the order or filter out a chart (see input$showPlot3).

    library(shiny)
    
    ui <- fluidPage(
      # App title ----
      titlePanel("Hello Shiny!"),
    
      # Sidebar layout with input and output definitions ----
      sidebarLayout(
    
        # Sidebar panel for inputs ----
        sidebarPanel(
    
          # Input: Slider for the number of bins ----
          sliderInput(inputId = "bins",
                      label = "Number of 'Waiting' bins:",
                      min = 1,
                      max = 50,
                      value = 30),
    
          sliderInput(inputId = "binsErupt",
                      label = "Number of 'Eruption' bins:",
                      min = 1,
                      max = 25,
                      value = 2),
    
          checkboxInput(inputId = "showPlot3", "Show third plot")
        ),
    
        # Main panel for displaying outputs ----
        mainPanel(
          uiOutput("ListOfCharts")
        )
      )
    )
    
    server <- function(input, output, session) {
      PutChartOnTop <- function(This, ChartList) {
        c(This, ChartList[ChartList != This])
      }
    
      ChartOrder <- reactiveVal(list("distPlot1", "timePlot2", "Plot3"))
    
      output$ListOfCharts <- renderUI({
        Order <- ChartOrder()
    
        ui <- lapply(Order, plotOutput)
        class(ui) <- c("shiny.tag.list", "list")
        return(ui)
      })
    
      observeEvent(
        input$bins,
        ChartOrder(PutChartOnTop("distPlot1", ChartOrder())))
    
      observeEvent(
        input$binsErupt,
        ChartOrder(PutChartOnTop("timePlot2", ChartOrder())))
    
      observeEvent(
        input$showPlot3,
        {
          if (input$showPlot3) {
            ChartOrder(PutChartOnTop("Plot3", ChartOrder())) # add plot on top
          } else {
            ChartOrder(ChartOrder()[ChartOrder() != "Plot3"]) # filter out plot 3
          }
        })
    
      output$distPlot1 <- renderPlot({
        x    <- faithful$waiting
        bins <- seq(min(x), max(x), length.out = input$bins + 1)
    
        hist(x, breaks = bins, col = "#75AADB", border = "white",
             xlab = "Waiting time to next eruption (in mins)",
             main = "Histogram of waiting times")
      })
    
    
    
      output$timePlot2 <- renderPlot({
        x    <- faithful$eruptions
        bins <- seq(min(x), max(x), length.out = input$binsErupt + 1)
    
        hist(x, breaks = bins, col = "#AADB75", border = "white",
             xlab = "Eruption time in mins",
             main = "Histogram of eruption duration")
    
      })
    
    
    
      output$Plot3 <- renderPlot({
        x <- faithful$waiting
        y <- faithful$eruptions
    
        plot(x, y, col = "#DB75AA", border = "white",
             xlab = "Waiting Time",
             main = "Waiting Times X Eruption Duration")
    
      })
    }
    
    shinyApp(ui, server)