Условный выбор в блестящем рендере - PullRequest
0 голосов
/ 28 апреля 2020

Я работаю над shiny app, который имеет 3 варианта отображения данных для используемых им данных. Для двух из этих опций пользователь должен выбрать один дополнительный вход из списка, но для третьего я бы хотел, чтобы пользователь выбрал два дополнительных входа вместо одного. Я знаю, что эти выборы могут быть реализованы в renderUI в части server. Тем не менее, то, что у меня есть в renderUI, - это единственная опция для выбора в зависимости от выбранной опции отображения фигуры, и я не знаю, как добавить дополнительную для третьей опции дисплея.

Вот мой пример:

suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(plotly))
suppressPackageStartupMessages(library(ggplot2))
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), type = sample(LETTERS[1:4], 1000, replace = T), sex = sample(c("F","M"), 1000, replace = T), age = sample(c("Y","O"), 1000, replace = T), 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)

#options to be used for subsetting point.df not on the fly
types <- c("all",unique(coordinate.df$type))
type.choices <- 1:length(types)
names(type.choices) <- types

sexes <- c("all",unique(coordinate.df$sex))
sex.choices <- 1:length(sexes)
names(sex.choices) <- sexes

ages <- c("all",unique(coordinate.df$age))
age.choices <- 1:length(ages)
names(age.choices) <- ages

color.code.groups <- c("type","sex","age")
feature.color.vec <- c("lightgray","darkred")

plot.type.choices <- c("Group Coordinate Plot","Feature Coordinate Plot","Feature Distribution Plot")

server <- function(input, output)
{
  chosen.types <- reactive({
    validate(
      need(input$types.choice != "",'Please choose at least one of the type checkboxes')
    )
    types.choice <- input$types.choice
    if("all" %in% types.choice) types.choice <- types[-which(types == "all")]
    types.choice
  })

  chosen.sexes <- reactive({
    validate(
      need(input$sexes.choice != "",'Please choose at least one of the sex checkboxes')
    )
    sexes.choice <- input$sexes.choice
    if("all" %in% sexes.choice) sexes.choice <- sexes[-which(sexes == "all")]
    sexes.choice
  })

  chosen.ages <- reactive({
    validate(
      need(input$ages.choice != "",'Please choose at least one of the age checkboxes')
    )
    ages.choice <- input$ages.choice
    if("all" %in% ages.choice) ages.choice <- ages[-which(ages == "all")]
    ages.choice
  })

  output$selection <- renderUI({
    if(input$plotType == "Group Coordinate Plot"){
      selectInput("selection", "Select Group to Color-Code by", choices = color.code.groups)
    } else if(input$plotType == "Feature Coordinate Plot"){
      selectInput("selection", "Select Feature to Display", choices = unique(feature.df$feature_id))
    } else if(input$plotType == "Feature Distribution Plot"){
      selectInput("selection", "Select Feature to Display", choices = unique(feature.df$feature_id))
    }
  })

  group.coordinate.plot <- reactive({
    if(!is.null(input$selection)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Group Coordinate Plot"){
        plot.df <- suppressWarnings(coordinate.df %>%
                                      dplyr::filter(type %in% plot.chosen.types & sex %in% plot.chosen.sexes & age %in% plot.chosen.ages) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age)))
        plot.df$group <- plot.df[,input$selection]
        plot.df$group <- factor(plot.df$group)
        group.coordinate.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$group,x=plot.df$x,y=plot.df$y,text=plot.df$hover.text,hoverinfo="text") %>%
                                                    plotly::layout(xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F),legend=list(itemsizing='constant')))
      }
    }
    group.coordinate.plot
  })

  feature.coordinate.plot <- reactive({
    if(!is.null(input$selection)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Feature Coordinate Plot"){
        feature.id <- input$selection
        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")) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age,"\n","value: ",value)))
        feature.coordinate.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,text=plot.df$hover.text,hoverinfo="text",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.coordinate.plot
  })

  feature.distribution.plot <- reactive({
    if(!is.null(input$selection)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Feature Distribution Plot"){
        feature.id <- input$selection
        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")) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age,"\n","value: ",value)))
        density.df <- do.call(rbind,lapply(sort(unique(plot.df$type)),function(t)
          ggplot2::ggplot_build(ggplot2::ggplot(plot.df %>% dplyr::filter(type == t),ggplot2::aes(x=value))+ggplot2::geom_density(adjust=1,colour="#A9A9A9"))$data[[1]] %>%
            dplyr::select(x,y) %>% dplyr::mutate(type = t))) %>% dplyr::left_join(dplyr::select(coordinate.df,type) %>% unique())
        density.df$type <- factor(density.df$type)
        feature.distribution.plot <- suppressWarnings(plotly::plot_ly(x=density.df$x,y=density.df$y,type='scatter',mode='lines',color=density.df$type) %>%
                                                        plotly::layout(title=plot.title,xaxis=list(title="Value",zeroline=F),yaxis=list(title="Density",zeroline=F)) %>%
                                                        plotly::add_annotations(text="type",xref="paper",yref="paper",x=1.02,xanchor="left",y=1.02,yanchor="top",legendtitle=T,showarrow=F))
      }
    }
    feature.distribution.plot
  })

  output$outPlot <- plotly::renderPlotly({
    if(input$plotType == "Group Coordinate Plot"){
      group.coordinate.plot()
    } else if(input$plotType == "Feature Coordinate Plot"){
      feature.coordinate.plot()
    } else if(input$plotType == "Feature Distribution Plot"){
      feature.distribution.plot()
    }
  })
}

ui <- fluidPage(

  # App title ----
  titlePanel("Results Explorer"),

  # Sidebar layout with a input and output definitions ----
  sidebarLayout(
    # Sidebar panel for inputs ----
    sidebarPanel(

      ## custom CSS for 3 column layout (used below for mechanics filter options)
      tags$head(
        tags$style(HTML(".multicol {-webkit-column-count: 3; /* Chrome, Safari, Opera */-moz-column-count: 3; /* Firefox */column-count: 3;}"))),
      ## use the css, assuming your long list of vars comes from global.R
      wellPanel(tags$div(class="multicol",checkboxGroupInput("types.choice", "Type",choices = names(type.choices),selected="all"))),
      wellPanel(tags$div(class="multicol",checkboxGroupInput("sexes.choice", "Sex",choices = names(sex.choices),selected="all"))),
      wellPanel(tags$div(class="multicol",checkboxGroupInput("ages.choice", "Age",choices = names(age.choices),selected="all"))),

      # select plot type
      selectInput("plotType", "Plot Type", choices = plot.type.choices),

      uiOutput("selection")

    ),

    # Main panel for displaying outputs ----
    mainPanel(
      # The plot is called out.plot and will be created in ShinyServer part
      plotly::plotlyOutput("outPlot")
    )
  )
)

shinyApp(ui = ui, server = server)

"Feature Distribution Plot" input$plotType - это параметр отображения, к которому я хотел бы добавить дополнительный выбор пользовательского ввода (который будет иметь параметр для графика плотности - текущий реализованный параметр или сюжет скрипки).

Есть идеи, как мне это добавить?

1 Ответ

0 голосов
/ 28 апреля 2020

Пожалуй, не самое элегантное решение, но разделение части renderUI, похоже, делает свое дело:

suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(plotly))
suppressPackageStartupMessages(library(ggplot2))
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), type = sample(LETTERS[1:4], 1000, replace = T), sex = sample(c("F","M"), 1000, replace = T), age = sample(c("Y","O"), 1000, replace = T), 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)

#options to be used for subsetting point.df not on the fly
types <- c("all",unique(coordinate.df$type))
type.choices <- 1:length(types)
names(type.choices) <- types

sexes <- c("all",unique(coordinate.df$sex))
sex.choices <- 1:length(sexes)
names(sex.choices) <- sexes

ages <- c("all",unique(coordinate.df$age))
age.choices <- 1:length(ages)
names(age.choices) <- ages

color.code.groups <- c("type","sex","age")
feature.color.vec <- c("lightgray","darkred")

plot.type.choices <- c("Group Coordinate Plot","Feature Coordinate Plot","Feature Distribution Plot")

server <- function(input, output)
{
  chosen.types <- reactive({
    validate(
      need(input$types.choice != "",'Please choose at least one of the type checkboxes')
    )
    types.choice <- input$types.choice
    if("all" %in% types.choice) types.choice <- types[-which(types == "all")]
    types.choice
  })

  chosen.sexes <- reactive({
    validate(
      need(input$sexes.choice != "",'Please choose at least one of the sex checkboxes')
    )
    sexes.choice <- input$sexes.choice
    if("all" %in% sexes.choice) sexes.choice <- sexes[-which(sexes == "all")]
    sexes.choice
  })

  chosen.ages <- reactive({
    validate(
      need(input$ages.choice != "",'Please choose at least one of the age checkboxes')
    )
    ages.choice <- input$ages.choice
    if("all" %in% ages.choice) ages.choice <- ages[-which(ages == "all")]
    ages.choice
  })

  output$type <- renderUI({
    if(input$plotType == "Group Coordinate Plot"){
      selectInput("type", "Select Group to Color-Code by", choices = color.code.groups)
    }
  })

  output$id <- renderUI({
    if(input$plotType == "Feature Coordinate Plot" | input$plotType == "Feature Distribution Plot"){
      selectInput("id", "Select Feature to Display", choices = unique(feature.df$feature_id))
    }
  })

  output$style <- renderUI({
    if(input$plotType == "Feature Distribution Plot"){
      selectInput("style", "Select Feature to Display", choices = c("density","violin"))
    }
  })

  group.coordinate.plot <- reactive({
    if(!is.null(input$type)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Group Coordinate Plot"){
        plot.df <- suppressWarnings(coordinate.df %>%
                                      dplyr::filter(type %in% plot.chosen.types & sex %in% plot.chosen.sexes & age %in% plot.chosen.ages) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age)))
        plot.df$group <- plot.df[,input$type]
        plot.df$group <- factor(plot.df$group)
        group.coordinate.plot <- suppressWarnings(plotly::plot_ly(marker=list(size=3),type='scatter',mode="markers",color=plot.df$group,x=plot.df$x,y=plot.df$y,text=plot.df$hover.text,hoverinfo="text") %>%
                                                    plotly::layout(xaxis=list(zeroline=F,showticklabels=F,showgrid=F),yaxis=list(zeroline=F,showticklabels=F,showgrid=F),legend=list(itemsizing='constant')))
      }
    }
    group.coordinate.plot
  })

  feature.coordinate.plot <- reactive({
    if(!is.null(input$id)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Feature Coordinate Plot"){
        feature.id <- input$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")) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age,"\n","value: ",value)))
        feature.coordinate.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,text=plot.df$hover.text,hoverinfo="text",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.coordinate.plot
  })

  feature.distribution.plot <- reactive({
    if(!is.null(input$id) & !is.null(input$style)){
      plot.chosen.types <- chosen.types()
      plot.chosen.sexes <- chosen.sexes()
      plot.chosen.ages <- chosen.ages()
      if(input$plotType == "Feature Distribution Plot"){
        feature.id <- input$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")) %>%
                                      dplyr::mutate(hover.text = paste0("coordinate_id: ",coordinate_id,"\n","type: ",type,"\n","sex: ",sex,"\n","age: ",age,"\n","value: ",value)))
        if(input$style == "density"){
          density.df <- do.call(rbind,lapply(sort(unique(plot.df$type)),function(t)
            ggplot2::ggplot_build(ggplot2::ggplot(plot.df %>% dplyr::filter(type == t),ggplot2::aes(x=value))+ggplot2::geom_density(adjust=1,colour="#A9A9A9"))$data[[1]] %>%
              dplyr::select(x,y) %>% dplyr::mutate(type = t))) %>% dplyr::left_join(dplyr::select(coordinate.df,type) %>% unique())
          density.df$type <- factor(density.df$type)
          feature.distribution.plot <- suppressWarnings(plotly::plot_ly(x=density.df$x,y=density.df$y,type='scatter',mode='lines',color=density.df$type) %>%
                                                          plotly::layout(title=plot.title,xaxis=list(title="Value",zeroline=F),yaxis=list(title="Density",zeroline=F)) %>%
                                                          plotly::add_annotations(text="type",xref="paper",yref="paper",x=1.02,xanchor="left",y=1.02,yanchor="top",legendtitle=T,showarrow=F))
        } else if(input$style == "violin"){
          feature.distribution.plot <- suppressWarnings(plotly::plot_ly(x=plot.df$type,y=plot.df$value,split=plot.df$type,type='violin',box=list(visible=T),points=T,color=plot.df$type,showlegend=F) %>%
                                                          plotly::layout(title=plot.title,xaxis=list(title="type",zeroline=F),yaxis=list(title="Value",zeroline=F)))
        }
      }
    }
    feature.distribution.plot
  })

  output$outPlot <- plotly::renderPlotly({
    if(input$plotType == "Group Coordinate Plot"){
      group.coordinate.plot()
    } else if(input$plotType == "Feature Coordinate Plot"){
      feature.coordinate.plot()
    } else if(input$plotType == "Feature Distribution Plot"){
      feature.distribution.plot()
    }
  })
}

ui <- fluidPage(

  # App title ----
  titlePanel("Results Explorer"),

  # Sidebar layout with a input and output definitions ----
  sidebarLayout(
    # Sidebar panel for inputs ----
    sidebarPanel(

      ## custom CSS for 3 column layout (used below for mechanics filter options)
      tags$head(
        tags$style(HTML(".multicol {-webkit-column-count: 3; /* Chrome, Safari, Opera */-moz-column-count: 3; /* Firefox */column-count: 3;}"))),
      ## use the css, assuming your long list of vars comes from global.R
      wellPanel(tags$div(class="multicol",checkboxGroupInput("types.choice", "Type",choices = names(type.choices),selected="all"))),
      wellPanel(tags$div(class="multicol",checkboxGroupInput("sexes.choice", "Sex",choices = names(sex.choices),selected="all"))),
      wellPanel(tags$div(class="multicol",checkboxGroupInput("ages.choice", "Age",choices = names(age.choices),selected="all"))),

      # select plot type
      selectInput("plotType", "Plot Type", choices = plot.type.choices),

      uiOutput("type"),
      uiOutput("id"),
      uiOutput("style")

    ),

    # Main panel for displaying outputs ----
    mainPanel(
      # The plot is called out.plot and will be created in ShinyServer part
      plotly::plotlyOutput("outPlot")
    )
  )
)

shinyApp(ui = ui, server = server)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...