Brilliant results from using the call function when observing output

I have a Shiny application where, based on the selected dataset (columns), the dynamic array is recalculated dynamically. The conversion result is used to display a different set of parameters to the user and to create a graph.

I am currently using observe() to read user selections, recalculate a dataset, and update the user interface. However, when displaying the output (graph), I have to recalculate again, since observe() returns nothing.

Is there a way to recalculate a data set only once?

I created a simple example to illustrate this:

 library(devtools) library(shiny) runGist('7333949') 

In server.R I would like to have one call to the custom function AggregateData in observe() and not call renderUI() .

Application Code:

server.R:

 # shiny server side code for each call shinyServer(function(input, output, session){ #update variable and group based on dataset observe({ require(sqldf) if (is.null(input$source_columns)) { obj <-TestData } else { obj<-AggregateData(TestData,Columns=input$source_columns) } var.opts<-namel(colnames(obj)) var.opts.original.slicers <- namel(colnames(TestData)) measures <- c('m1','m2','m3','m4','m5') var.opts.slicers <- var.opts[!(var.opts %in% c(measures,'x'))] var.opts.original.slicers <- var.opts.original.slicers[!(var.opts.original.slicers %in% c(measures,'x'))] var.opts.measures <- var.opts[var.opts %in% measures] updateSelectInput(session, "source_columns", choices = var.opts.original.slicers, selected=var.opts.slicers) updateSelectInput(session, "xaxis", choices = var.opts.slicers,selected="x") updateSelectInput(session, "yaxis", choices = var.opts.measures,selected="m1") }) output$plot <- renderUI({ plotOutput("p") }) #plotting function using ggplot2 output$p <- renderPlot({ require(ggplot2) obj <- AggregateData(TestData,Columns=input$source_columns) p <- PlotData(obj,x=input$xaxis, y=input$yaxis) print(p) }) }) 

ui.R:

 shinyUI(pageWithSidebar( # title headerPanel("Analysis setup"), #input sidebarPanel ( selectInput("source_columns","Source Columns:", "Loading...",multiple=TRUE), selectInput("xaxis","X Axis:", "Loading..."), selectInput("yaxis","Y Axis:", "Loading...") ), # output mainPanel( #h3('Vintage Analysis'), uiOutput("plot") # depends on input ) )) 

global.R:

 #initialize library(ggplot2) TestData <- data.frame( a = rep(LETTERS[1:4],10), b = rep(c('A','B'),20), c = rep(LETTERS[1:5],each=8), d = rep(c('A','B'),2,each=10), m1 = rnorm(40), m2 = rnorm(40), m3 = rnorm(40), m4 = rnorm(40), m5 = rnorm(40), x = rep(1:5,each=8) ) #helper function (convert vector to named list) namel<-function (vec){ tmp<-as.list(vec) names(tmp)<-as.character(unlist(vec)) tmp } # Function to aggregate data based on selected columns (Source Columns) AggregateData <- function(data,Columns=NA) { require(sqldf) if (all(is.na(Columns))) { sql <- "select sum(m1) as m1, sum(m2) as m2, sum(m3) as m3, sum(m4) as m4, sum(m5) as m5, x from TestData group by x" sqldf(sql) } else { sql <- paste("select ", paste(Columns, collapse =','), ", sum(m1) as m1, sum(m2) as m2, sum(m3) as m3, sum(m4) as m4, sum(m5) as m5, x from TestData group by ",paste(Columns, collapse =','),", x") sqldf(sql) } } # Function to plot data PlotData <- function(data,x="x",y="m1") { ggplot(data, aes_string(x=x, y=y)) + geom_line() } 
+7
r shiny
source share
2 answers

observe does not return anything, but still it can create something. I solved this by assigning obj global environment using the <<- operator. In server.R I have:

 obj<<-AggregateData(TestData,Columns=input$source_columns) 

Then in UI.r I can call obj directly in ggplot, without requiring to call AggregateData again.

0
source share

Use reactiveValues() :

 shinyServer(function(input, output, session){ #update variable and group based on dataset values <- reactiveValues() observe({ require(sqldf) if (is.null(input$source_columns)) { values$obj <-TestData } else { values$obj<-AggregateData(TestData,Columns=input$source_columns) } ... }) output$plot <- renderUI({ plotOutput("p") }) #plotting function using ggplot2 output$p <- renderPlot({ require(ggplot2) obj <- values$obj p <- PlotData(obj,x=input$xaxis, y=input$yaxis) print(p) }) }) 
+6
source share

All Articles