Combining renderUI, dataTableOutput, renderDataTable, and reactive to allow user selection from either a list or a DT with filters

Hi,

I have data which I want a shiny app to allow exploring with the selection of s specific feature from the data either from a list using renderUI and selectInput or from a table using DT::renderDT and DT::dataTableOutput wrapped inside renderUI. Since the table to be displayed by the DT::renderDT option is large (in my real data, not in the example below), I'd like to enable filtering it.

Here's what I have so far:


suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(plotly))
suppressPackageStartupMessages(library(shiny))


#data.frames to be used in the server
set.seed(1)
coordinate.df <- data.frame(coordinate_id = paste0("c", 1:1000),x = rnorm(1000), y = rnorm(1000), stringsAsFactors = F)
feature.df <- data.frame(coordinate_id = rep(paste0("c", 1:1000), 10), feature_id = rep(paste0("f", 1:10), 1000), value = rnorm(10*1000), stringsAsFactors = F)
feature.rank.df <- feature.df %>% dplyr::select(feature_id) %>% unique() %>% dplyr::mutate(rank=sample(1:10,10,replace = F)) %>% dplyr::arrange(rank)

feature.color.vec <- c("lightgray","darkred")
plot.types <- c("list","table")

server <- function(input, output)
{

  output$feature.idx <- renderUI({
    if(input$plotType == "table"){
      feature.table.widget <- DT::datatable(feature.rank.df,selection="none",rownames=F,style="bootstrap",options=list(columnDefs=list(list(searchable=F,targets=0))),filter='top')
      output$feature.table <- DT::renderDT(feature.table.widget,server=T,selection="single")
      DT::dataTableOutput("feature.table")
    }
  })
  
  output$feature.id <- renderUI({
    if(input$plotType == "list"){
      selectInput("feature.id", "Select Feature", choices = feature.rank.df$feature_id)
    }
  })
  

  feature.idx.plot <- reactive({
    if(!is.null(input$feature.table_rows_selected)){
      feature.id <- feature.rank.df$feature_id[input$feature.table_rows_selected]
      plot.title <- feature.id
      plot.df <- suppressWarnings(feature.df %>% dplyr::filter(feature_id == feature.id) %>%
                                    dplyr::left_join(coordinate.df,by=c("coordinate_id"="coordinate_id")))
      feature.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$value,x=plot.df$x,y=plot.df$y,showlegend=F,colors=colorRamp(feature.color.vec)) %>%
            plotly::layout(title=plot.title,xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F)) %>%
            plotly::colorbar(limits = c(min(plot.df$value,na.rm=T),max(plot.df$value,na.rm=T)),len=0.4,title="Value"))
    } else{
      feature.plot <- NULL
    }
    return(feature.plot)
  })

  feature.id.plot <- reactive({
    if(!is.null(input$feature.id)){
      feature.id <- input$feature.id
      plot.title <- feature.id
      plot.df <- suppressWarnings(feature.df %>% dplyr::filter(feature_id == feature.id) %>%
                                    dplyr::left_join(coordinate.df,by=c("coordinate_id"="coordinate_id")))
      feature.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$value,x=plot.df$x,y=plot.df$y,showlegend=F,colors=colorRamp(feature.color.vec)) %>%
                                         plotly::layout(title=plot.title,xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F)) %>%
                                         plotly::colorbar(limits = c(min(plot.df$value,na.rm=T),max(plot.df$value,na.rm=T)),len=0.4,title="Value"))
    } else{
      feature.plot <- NULL
    }
    return(feature.plot)
  })
  

  output$outPlot <- plotly::renderPlotly({
    if(input$plotType == "table"){
      feature.idx.plot()
    } else if(input$plotType == "list"){
      feature.id.plot()
    }
  })
}


ui <- fluidPage(
  titlePanel("Results Explorer"),
  sidebarLayout(
    sidebarPanel(
      selectInput("plotType", "Plot Type", choices = plot.types),
      uiOutput("feature.idx"),
      uiOutput("feature.id")
    ),
    mainPanel(
      plotly::plotlyOutput("outPlot")
    )
  )
)

shinyApp(ui = ui, server = server)

While it does allow filtering of the table, a row selection does not result in a plot display, and it's not clear to me which row index input$feature.table_rows_selected is referring to (the filtered table or the entire table), and so is the feature.id <- feature.rank.df$feature_id[input$feature.table_rows_selected] call inside the reactive part that is meant to plot the data given the table row selection even correct?

I should mention that if I comment out:
feature.table.widget <- DT::datatable(feature.rank.df,selection="none",rownames=F,style="bootstrap",options=list(columnDefs=list(list(searchable=F,targets=0))),filter='top')

And replace:
output$feature.table <- DT::renderDT(feature.table.widget,server=T,selection="single")

with:
output$feature.table <- DT::renderDT(feature.rank.df,server=T,selection="single")

It works fine, albeit with no filtering.

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.