7

I am working on a Shiny app and as I go I have been adding figures and tables in a haphazard way. I would like to have a better framework so that I can flexibly add reactive figures and tables to the output as it develops further.

At the moment I have been using tabPanel and fluidrow to add additional a summary table and a second plot. However I have had trouble adapting this. For example I currently generate 3 plots but have only able to plot 2 at a time. Could anyone show me a way to modify the code to display all three plots (distPlot1, distPlot2, distPlot3) and the summary table on the same page? Ideally in a way that it would be simple to add additional tables and plots in the future.

Thank you in advance.

My current code is below.

ui.R

library(reshape2)
library(shiny)
library(ggplot2)
# Define UI for application that draws a histogram
fluidPage(

  # Application title
  titlePanel("Mutation Probability"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("x", "Probability of mutation (per bp):", 
                  min=1/1000000000000, max=1/1000, value=1/10000000),

      sliderInput("y", "Size of region (bp):", 
                  min = 10, max = 10000, value = 1000, step= 100),

      sliderInput("z", "Number of samples:", 
                  min = 1, max = 100000, value = 1000, step= 10)

    ),

    # Show a plot of the generated distribution
    mainPanel(
      tabsetPanel(
        tabPanel("Plot",
          fluidRow(
            splitLayout(cellWidths = c("50%", "50%"), plotOutput("distPlot1"), plotOutput("distPlot3"), plotOutput("distPlot3)"))
          )),
        tabPanel("Summary",  verbatimTextOutput("summary"))
      )
    )
  )
)

server.R

server <- function(input, output) {

  mydata <- reactive({
    x <- input$x
    y <- input$y
    z <- input$z
    Muts <- as.data.frame(rpois(100,(x*y*z)))
    Muts
  })


  output$distPlot1 <- renderPlot({
    Muts <- mydata()
    ggplot(Muts, aes(Muts)) + geom_density() +xlab("Observed variants")
  })

  output$distPlot2 <-renderPlot({
    Muts <- mydata()
    ggplot(Muts, aes(Muts)) + geom_histogram() + xlab("Observed variants")
  })
  #get a boxplot working
  output$distPlot3 <-renderPlot({
    Muts <- mydata()
    ggplot(data= melt(Muts), aes(variable, value)) + geom_boxplot() + xlab("Observed variants")
  })

  output$summary <- renderPrint({
    Muts <- mydata()
    summary(Muts)
  })


}
Mike Wise
  • 22,131
  • 8
  • 81
  • 104
user964689
  • 812
  • 7
  • 20
  • 40
  • Shouldn't you change the split widths to accommodate three plots? Instead of 50%, don't you need 33% to get three in a row? – Ryan Morton Mar 28 '17 at 20:41
  • I tried that but it didn't seem to work, just made the first 2 plots smaller. But possible I didn't do it correctly. – user964689 Mar 29 '17 at 08:03

1 Answers1

9

I like laying out the graphics in the server using tools like grid.arrange from the package gridExtra or the package cowplot - they offer a lot of layout flexiblity. This for example:

library(reshape2)
library(shiny)
library(ggplot2)
library(gridExtra)
# Define UI for application that draws a histogram

u <- fluidPage(

  # Application title
  titlePanel("Mutation Probability"),

  # Sidebar with a slider input for the number of bins
  sidebarLayout(
    sidebarPanel(
      sliderInput("x", "Probability of mutation (per bp):", 
                  min=1/1000000000000, max=1/1000, value=1/10000000),

      sliderInput("y", "Size of region (bp):", 
                  min = 10, max = 10000, value = 1000, step= 100),

      sliderInput("z", "Number of samples:", 
                  min = 1, max = 100000, value = 1000, step= 10)

    ),

    # Show a plot of the generated distribution
    mainPanel(
      tabsetPanel(
        tabPanel("Plot",
                 fluidRow(
                   plotOutput("distPlot4"),
                   verbatimTextOutput("summary"))
                 )),
        tabPanel("Summary",  verbatimTextOutput("summary1"))
      )
    )
  )
)
s <- function(input, output) {

  mydata <- reactive({
    x <- input$x
    y <- input$y
    z <- input$z
    Muts <- as.data.frame(rpois(100,(x*y*z)))
    Muts
  })
  output$distPlot4 <- renderPlot({
    Muts <- mydata()
    p1 <- ggplot(Muts, aes(Muts)) + geom_density() +xlab("Observed variants")
    p2 <- ggplot(Muts, aes(Muts)) + geom_histogram() + xlab("Observed variants")
    p3 <- ggplot(data= melt(Muts), aes(variable, value)) + geom_boxplot() + xlab("Observed variants")
    grid.arrange(p1,p2,p3, ncol=3,widths = c(2,1,1))
  })
  output$summary <- renderPrint({
    Muts <- mydata()
    summary(Muts)
  })
}
shinyApp(u,s)

which yields:

enter image description here

For summary tables, I just add them to the bottom, one after the other, not much else you can do there I think.

Mike Wise
  • 22,131
  • 8
  • 81
  • 104
  • 1
    This is great thanks. Just the kind of flexibility I was looking for. – user964689 Mar 29 '17 at 08:04
  • Can this be done while defining the size, location, and functionality of each plot? –  Jun 15 '17 at 17:13
  • 1
    Sure but exactly how to do it best depends on the details. – Mike Wise Jun 15 '17 at 17:21
  • What's the best way to show you my UI without creating a new post? –  Jun 15 '17 at 17:28
  • I made adjustments to a related post: https://stackoverflow.com/questions/44571813/insert-function-within-multiple-plots-in-r-shiny Please refer to the "Edited" portion of the original post for details. –  Jun 15 '17 at 17:36
  • 1
    I will have a look in the morning, on vacation at the moment so my editing and testing capabilities are severely limited :) – Mike Wise Jun 15 '17 at 18:07
  • Enjoy your vacation, and no pressure. I think I may have figured out a portion of my problem. Thanks again in advance. –  Jun 15 '17 at 18:27