Search code examples
rplotshinyuser-inputselectinput

How can I show different plots depending on the user's input in Shiny?


I have this data frame:

> df
  genes  enst  x  y
1 Gene1 ENST1 25 14
2 Gene1 ENST2 60 25
3 Gene1 ENST3 12  5
4 Gene2 ENST1  9 34
5 Gene2 ENST2 14 12
6 Gene3 ENST1 10  1

I am trying to create a Shiny App which allows me to select genes and transcripts. If you select a gene (for example, Gene1), you will have an option to select which transcript do you want (in this case, ENST1, ENST2, ENST3). image 1

The thing is that I want to draw 2 plots. If you click "gene" (level:gene) it will sum all the values from that gene. For example, for the first gene, which has 3 transcripts, the total value of x will be 20+60+12=92 and the total value of y will be 14+25+5=44). So the values for plotting gene 1 will be: x=92 and y=44.

Image 2

Moreover, I would like to plot EACH transcript. For example, if you select "Gene1" and "Transcript 1", the plot will use x=25 and y=14. However, If the user decides to choose two transcripts, the user will see 2 plots. Or if the user chooses 3 transcripts, the user will see the 3 different plots.

image 3

Right now, with my code: If you select the gene, you will get the plot for the gene. image 4

However, it will show all the transcripts in the same plot. And I only want to show one transcript (or more, if the user wants) image 5

I don't know how to continue.

On the other hand, there are two things that I don't know how to implement.

  • An action button "see the plot". --- if you click on it, it will show you the plot.
  • A radiobutton "level" --- if you click on gene, it only will show you the gene plots. However, if you click on transcript, it will show you the transcript plots.

Could anyone help me? Thanks in advance

My code:

library(shiny)

################ DATA #############################
genes<- c("Gene1", "Gene1", "Gene1", "Gene2", "Gene2", "Gene3")
enst <- c("ENST1", "ENST2", "ENST3", "ENST1", "ENST2", "ENST1")
x <- c(25, 60, 12, 9, 14, 10)
y <- c(14, 25, 5, 34, 12, 1)
df<- data.frame(genes, enst, x, y)

###################################################

ui <- fluidPage(
  
  # Application title
  titlePanel("Barplot"),
  
  sidebarLayout(
    sidebarPanel(
      uiOutput("selected_gene"),
      uiOutput("selected_transcript"),
      radioButtons("level", "Level:",
                   c("Gene" = "Gene",
                     "Transcript" = "Transcript")),
      h5(strong("If you want to see the plot, you have to click the button")),
      actionButton("add_plot", "See the plot"),
    ),
    
    mainPanel(
      plotOutput("plot"),
      plotOutput("plot2"),
  
      tableOutput("table1"),
      tableOutput("table2")
    )
  )
)


server <- function(session, input, output) {
  
  
  # This function gives us the list of genes.
  genes_list <- reactive({
    df$genes
    })
  
  transcripts_list <- reactive({
    
    transcripts <- subset(df, df$genes==input$gene)
    transcripts <- transcripts[,2]
    return(transcripts)
  })
  
  # This function give us a select list input, in order to be able to select the gene that we want to see
  output$selected_gene <- renderUI({
    selectizeInput(inputId = "gene", "Select one gene", choices=genes_list(), options=list(maxOptions = length(genes_list())))
  })
  
  output$selected_transcript <- renderUI({
    selectizeInput(inputId = "transcript", "Select one transcript", choices=transcripts_list(), options=list(maxOptions = length(transcripts_list())), multiple=T)
  })
  
  
  gene_values <- reactive({
    
    values <- subset(df, df[1]==input$gene)
    values$enst <- NULL
    
    if(nrow(values)>1){ #for those genes who have more than 1 transcript
      values_new <- values[2:length(values)] 
      values_new <- as.data.frame(t(colSums(values_new))) # sum the columns, transpose and transform into a dataframe
      
      gene <- values[1,] #we take the first row, only one gene but all the info.
      
      values <- cbind(values_new, gene[1]) # we bind both dataframes, however, we only want the gene name
      values <- values[,c("genes",setdiff(names(values),"genes"))] # we move the last column at the beginning
    }
    return(values)
    
  })
    
  transc_values <- reactive({

    values <- subset(df, df[1]==input$gene)
    values$genes <- NULL
  
    return(values)
  })
  
  plot_genes <- reactive({
    gene_values <- gene_values()
    barplot(c(gene_values$x, gene_values$y))
    
  })
  
  plot_transc <- reactive({
    transc_values <- transc_values()
    barplot(c(transc_values$x, transc_values$y))
    
  })
  
  
  v <- reactiveValues(plot = NULL)
  
  observeEvent(input$add_plot, {
    if(input$level == "Gene"){
      v$plot <- plot_genes()
    }
    if(input$level == "Transcript"){
      v$plot <- plot_transc()
    }
  })
  
  # This function will draw the plot
  # output$plot <- renderPlot({
  #   if (is.null(v$plot)){
  #     return()
  #   }
  #   v$plot
  # })
  
  

  output$table1 <- renderTable(gene_values())
  output$table2 <- renderTable(transc_values())
  
  output$plot <- renderPlot(plot_genes())
  output$plot2 <- renderPlot(plot_transc())
  
  
}

shinyApp(ui, server)

Solution

  • Perhaps you can start with this and modify according to your needs.

    library(shiny)
    library(ggplot2)
    library(DT)
    ################ DATA #############################
    genes<- c("Gene1", "Gene1", "Gene1", "Gene2", "Gene2", "Gene3")
    enst <- c("ENST1", "ENST2", "ENST3", "ENST1", "ENST2", "ENST1")
    x <- c(25, 60, 12, 9, 14, 10)
    y <- c(14, 25, 5, 34, 12, 1)
    df<- data.frame(genes, enst, x, y)
    
    ###################################################
    
    ui <- fluidPage(
      
      # Application title
      titlePanel("Histogram"),
      
      sidebarLayout(
        sidebarPanel(
          uiOutput("selected_gene"),
          uiOutput("selected_transcript"),
          radioButtons("level", "Level:",
                       c("Gene" = "Gene",
                         "Transcript" = "Transcript")),
          h5(strong("If you want to see the plot, you have to click the button")),
          div(actionButton("add_plot", "See the plot"), 
              actionButton("table", "See the table"),
              actionButton("clear", "Clear All")
              )
        ),
        
        mainPanel(
          plotOutput("plot"),
          DTOutput("table")
        )
      )
    )
    
    
    server <- function(input, output, session) {
      
      
      ## This function gives us the list of genes.
      genes_list <- reactive({
        unique(df$genes)
      })
      
      transcripts_list <- reactive({
        req(input$gene)
        transcripts <- subset(df, df$genes==input$gene)
        transcripts <- transcripts[,2]
        return(unique(transcripts))
      })
      
      # This function give us a select list input, in order to be able to select the gene that we want to see
      output$selected_gene <- renderUI({
        selectizeInput(inputId = "gene", "Select one gene", choices=genes_list(), options=list(maxOptions = length(genes_list())))
      })
      
      output$selected_transcript <- renderUI({
        selectizeInput(inputId = "transcript", "Select one transcript", choices=transcripts_list(), options=list(maxOptions = length(transcripts_list())), multiple=F)
      })
      
      
      gene_values <- reactive({
        req(input$gene)
        values <- subset(df, df[1]==input$gene)
        values$enst <- NULL
        
        if(nrow(values)>1){ #for those genes who have more than 1 transcript
          values_new <- values[2:length(values)] 
          values_new <- as.data.frame(t(colSums(values_new))) # sum the columns, transpose and transform into a dataframe
          
          gene <- values[1,] #we take the first row, only one gene but all the info.
          
          values <- cbind(values_new, gene[1]) # we bind both dataframes, however, we only want the gene name
          values <- values[,c("genes",setdiff(names(values),"genes"))] # we move the last column at the beginning
        }
        return(values)
        
      })
      
      transc_values <- reactive({
        req(input$transcript)
        values <- subset(df, df[2]==input$transcript)
        values$genes <- NULL
        
        return(values)
      })
      
      mydata <- reactive({
        req(input$level)
        if(input$level == "Gene"){
          df <- req(gene_values())
        }else if(input$level == "Transcript"){
          df <- req(transc_values())
        }else df <- NULL
        df
      })
      
      # plot_genes <- reactive({
      #   gene_values <- req(gene_values())
      #   barplot(c(gene_values$x, gene_values$y))
      #   
      # })
      # 
      # plot_transc <- reactive({
      #   transc_values <- req(transc_values())
      #   barplot(c(transc_values$x, transc_values$y))
      #   
      # })
      
      
      v <- reactiveValues(plot = NULL, table=NULL)
      
      observeEvent(input$add_plot, {
        v$plot <- ggplot(mydata(), aes(x=x,y=y)) + geom_bar(stat = "identity")
        v$table <- NULL  ### display only plot
      },ignoreInit = TRUE)
      
      observeEvent(input$table, {
        v$table <- req(mydata())
        v$plot <- NULL   ### display only table
      },ignoreInit = TRUE)
      
      observeEvent(input$clear, {
        v$table <- NULL
        v$plot <- NULL
      },ignoreInit = TRUE)
      
      ##  This function will draw the plot
      output$plot <- renderPlot({ v$plot })
      output$table <- renderDT({ v$table })
      
    }
    
    shinyApp(ui, server)