Combining renderUI, dataTableOutput, renderDataTable, and reactive

怎甘沉沦 提交于 2020-04-30 06:28:21

问题


This is somewhat of an expansion of this post:

I would like to have the DT::renderDataTable inside the renderUI and then have the output of the renderUI used in the reactive.

This is what I'm doing:

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")

server <- function(input, output)
{

  output$feature.idx <- renderUI({
    output$feature.table <- DT::renderDataTable(feature.rank.df, server = FALSE, selection = "single")
    DT::dataTableOutput("feature.table")
  })

  feature.plot <- reactive({
    if(!is.null(input$feature.idx)){
      feature.id <- feature.rank.df$feature_id[input$feature.idx]
      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"))
    }
    feature.plot
  })

  output$outPlot <- plotly::renderPlotly({
    feature.plot()
  })
}


ui <- fluidPage(
  titlePanel("Results Explorer"),
  sidebarLayout(
    sidebarPanel(
      uiOutput("feature.idx")
    ),

    mainPanel(
      plotly::plotlyOutput("outPlot")
    )
  )
)

shinyApp(ui = ui, server = server)

It does load the feature.rank.df data.frame but it then prints this error message to the main panel:

Error: no applicable method for 'plotly_build' applied to an object of class "c('reactiveExpr', 'reactive')"

And nothing gets plotted upon row selection in the table in the side panel.

Any idea what the solution is?


回答1:


You can fix this by replacing your server function by the code below.

  • refer to the selected feature by input$feature.table_rows_selected
  • keep the reactive feature.plot code in the renderPlotly function
server <- function(input, output)
{
    output$feature.idx <- renderUI({
        output$feature.table <-
            DT::renderDataTable(feature.rank.df,
                                server = FALSE,
                                selection = "single")
        DT::dataTableOutput("feature.table")
    })

    output$outPlot <- plotly::renderPlotly({
        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"
                        )
                )
            feature.plot
        }

    })
}

Edit:

Alternatively, you can keep the feature.plot as a reactive, like this:

server <- function(input, output)
{

    output$feature.idx <- renderUI({
        output$feature.table <- DT::renderDataTable(feature.rank.df, server = FALSE, selection = "single")
        DT::dataTableOutput("feature.table")
    })

    feature.plot <- reactive({
        if (!is.null(input$feature.table_rows_selected)) {
            feature.id <-
                feature.rank.df$feature_id[input$feature.table_rows_selected]
            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.df$feature_id[1],
                            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"
                        )
                )
        }
        return(feature.plot)
    })

    output$outPlot <- plotly::renderPlotly({
        req(feature.plot(), input$feature.table_rows_selected)
        feature.plot()
    })
}


来源:https://stackoverflow.com/questions/61493318/combining-renderui-datatableoutput-renderdatatable-and-reactive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!