我在Shiny App中有一个看似很小但棘手的问题,它具有反应功能。

该应用程序旨在在选择公司时显示lineChart,在选择“全部”时显示所有公司的条形图。例如,选择时:

在ui中按类别1 = 3筛选和按类别1:2筛选,下拉列表中仅剩4家公司,然后我希望能够在下拉列表中选择公司A以获取公司A的折线图。

问题是,当我选择公司A时,它将显示公司A的lineChart 1秒钟,然后跳回“全部”。

我认为问题在于以下几行:

output$firm <- renderUI({
   selectInput("firm", "Filter by Firm:",
            choices = c("All",as.character(unique(subset_data()$FIRM))))
  })


我要求的选择是“全部”和“确认X”。它首先为公司X创建lineChart,然后在“所有”下创建图表。因此,我试图从选择中删除“全部”,但这没有用。

任何帮助,不胜感激!
谢谢

这是一个可重现的示例:

首先创建样本数据:

set.seed(1)
df <- data.frame(FIRM=rep(LETTERS[1:7],each=10), CATEG_1=rbinom(70,4,0.9),CATEG_2=rbinom(70,1,0.2),date=as.Date("2014-01-01")+1:10,y1=sample(1:100,70))


ShinyApp:

library(shiny)
library(rCharts)
library(doBy)
library(plyr)

shinyApp(ui =
shinyUI(pageWithSidebar(

# Application title
headerPanel("Example"),

           sidebarPanel(
         uiOutput("firm"),
        #  selectInput("firm", "Filter by firm:",
        #   choices = unique(as.character(df))),
         selectInput("categ_1", "Filter by Category 1:",
                     choices = c("All",unique(as.character(df$CATEG_1)))),
         selectInput("date", "Filter by Date:",
                     choices = c("All","Last 28 Days","Last Quarter")),
         selectInput("categ_2", "Filter by Category 2:",
                     choices = c("All",unique(as.character(df$CATEG_2))))
       ), #sidebarPanel

       mainPanel(
         h4("Example plot",style = "color:grey"),
         showOutput("plot", "nvd3")
       ) # mainPanel
     ) #sidebarLayout
 ) #shinyU
 ,
server = shinyServer(function(input, output, session) {

subset_data <- reactive({df <- filter_data(df,input$firm,
                                         input$date,
                                         input$categ_1,
                                         input$categ_2)
                       shiny::validate(need(!is.null(df),"No data to display"))
                       return(df)})

  output$firm <- renderUI({
   selectInput("firm", "Filter by Firm:",
            choices = c("All",as.character(unique(subset_data()$FIRM))))
  })

  output$plot<-renderChart2({ build_plot(subset_data()) })

##############
#below are the functions used in the code
##############

 # function for date subsetting

  filter_date<-function(df,dateRange="All"){
  filt <- df
  td <- max(as.Date(filt$date))
  if (dateRange=='Last 28 Days'){filt <-filt[filt$date>=(td-28),]}
  if (dateRange=='Last Quarter'){filt <-filt[filt$date>=(td-84),]}
  return(filt)
   }  # filter by date

 # function for data subsetting

  filter_data<-function(df,firm=NULL,dateRange="All",categ_1=NULL,categ_2=NULL)
  {
  filt<-filter_date(df,dateRange)

  if (!is.null(firm)) {
  if(firm!='All') {filt <- filt[filt$FIRM==firm,]}
  }
  if (!is.null(categ_1)){
  if (categ_1!='All') {filt <- filt[filt$CATEG_1==categ_1,]}
  }
  if (!is.null(categ_2)) {
  if (categ_2!='All') {filt <- filt[filt$CATEG_2==categ_2,]}
  }

  if(nrow(filt)==0) {filt <- NULL}
  return(filt)
  } # prepare data to be plotted

# function to create plot

  build_plot <- function(df) {
  plotData<-df
  # If 1 partner selected, time series is shown
  if (length(as.character(unique(plotData$FIRM)))==1) {

  tabledta<-summaryBy(y1~FIRM+date,data=plotData,FUN=sum,keep.names=TRUE)

  filler = expand.grid(FIRM=as.character(unique(df$FIRM)),
                     date=seq(min(tabledta$date),max(tabledta$date),by='1 day'))
  df = merge(filler,
           tabledta,
           by=c('date','FIRM'),
           all.x=T)
  df[is.na(df)]=0
  p <- nPlot(y1 ~ date, group = 'FIRM', data = df, type = 'lineChart')
  p$chart(margin=list(left=150))
  p$yAxis(showMaxMin = FALSE)
  p$xAxis(tickFormat ="#!function(d) {return d3.time.format('%Y-%m-%d')(new Date(d * 24 * 60 * 60 * 1000));}!#")
  p
  }
  # If "All" partners are selected, barchart of Top 5 is shown
  else{
  SummaryTab<-aggregate(y1~FIRM,data=plotData,FUN=sum)
  SummaryTab$rank=rank(SummaryTab$y1)
  SummaryTab$rank[SummaryTab$rank>5]<-6

  if (length(SummaryTab$rank)>5) {
  #Top 5 partners in terms of y1 are shown
  top5<-SummaryTab[SummaryTab$rank<=5,]
  # other partners are collapsed, shown as 1 entry

  others<-aggregate(y1~rank,data=SummaryTab,FUN=sum)
  others<-others[others$rank==6,]
  others$FIRM<-"Others"

  # Create the summarytable to be plotted
  plotData=rbind(top5,others)}

  tabledta<-summaryBy(y1~FIRM,data=plotData,FUN=sum,keep.names=TRUE)
  tabledta<-arrange(tabledta,y1)
  #   if(is.null(tabledta)) {print("Input is an empty string")}

  p <- nPlot(y1 ~ FIRM,data = tabledta, type = 'multiBarHorizontalChart')
  p$chart(margin=list(left=150))
  p$yAxis(showMaxMin = FALSE)
  p
  }

  }
  }) #shinyServer
  )

最佳答案

问题在于output $ firm在代码中是自反应的,因为它取决于input $ firm。

output $ firm表达式为input $ firm生成一个用户界面,该界面会自动触发对依赖于input $ form的所有反应式表达式的重新评估。这样的反应性表达式之一是output $ firm本身(它取决于通过subset_data()的input $ firm),因此每次对output $ firm的调用都将导致其递归重新评估。

您需要隔离出subset_data()表达式,这将防止触发subset_data()中的更改:

output$firm <- renderUI({
 input$date
 input$categ_1
 input$categ_2
 selectInput("firm", "Filter by Firm:",
         choices = c("All",as.character(unique(isolate(subset_data()$FIRM)))))
})


请注意,我插入了几个input $ ...行,以确保output $ firm将在这些输入的任何更改时触发。

08-26 23:16