I have a Shiny application where based on selected options (columns) dataset is recalculated dynamically. Result of recalculation is used for displaying another set of options to user and to create a plot.
Currently I'm using observe()
to read user selection, recalculate dataset and update UI. However, when displaying output (plot), I have to do the recalculation again, as observe()
does not return anything.
Is there a way how to recalculate the dataset only once?
I've created simple example to illustrate this:
library(devtools)
library(shiny)
runGist('7333949')
In server.R
I would like to have one call to custom function AggregateData
in observe()
and no call in renderUI()
.
App 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()
}
An observer is like a reactive expression in that it can read reactive values and call reactive expressions, and will automatically re-execute when those dependencies change. But unlike reactive expressions, it doesn't yield a result and can't be used as an input to other reactive expressions.
Simply call shinyalert() with the desired arguments, such as a title and text, and a modal will show up. In order to be able to call shinyalert() in a Shiny app, you must first call useShinyalert() anywhere in the app's UI.
Shiny uses the function fluidPage to create a display that automatically adjusts to the dimensions of your user's browser window. You lay out the user interface of your app by placing elements in the fluidPage function.
Arguments. inputId. The input slot that will be used to access the value. label. Display label for the control, or NULL for no label.
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)
})
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With