Use R shiny to simulate CLT by using different distribution - r

library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
titlePanel("Central Limit Theorem Simulation"),
sidebarLayout(
sidebarPanel(
numericInput("sample.size", "Size of each random sample",
value = 30, min = 1, max = 100, step = 1),
sliderInput("simulation", "THe number of simulation",
value = 100, min = 100, max = 1000, step = 1),
selectInput("sample.dist", "Population Distribution where each sample is from",
choices = c("Binomial","Poisson", "Normal", "Uniform") ),
numericInput("bins", "Number of bins in the histogram",
value = 20, min = 1, max = 50, step = 1),
submitButton(text = "Submit")
),
mainPanel(
h3('Illustrating outputs'),
h4('mean of random sample mean'),
textOutput(outputId = "output_mean" ),
h4('variance of random sample mean'),
textOutput(outputId = "output_var"),
h4("Table"),
tableOutput(outputId = "output_table"),
h4('histogram of random normal sample'),
plotOutput(outputId = "output_hist")
)
)
))
server <- shinyServer(function(input, output) {
# Return the random sample
rsample <- ifelse(
input$sample.dist == "Binomial", rbinom(input$sample.size * input$simulation, 1, 0.5),
ifelse(input$sample.dist == "Poisson", rpois(input$sample.size * input$simulation, 1),
ifelse(input$sample.dist == "Normal", rnorm(input$sample.size * input$simulation),
runif(input$sample.size * input$simulation) ) ) )
# Return the random sample matrix
rsample.matrix <- matrix(rsample, nrow = input$simulation)
# output mean of sample mean
output$output_mean <- renderText({
sample.mean <- rowMeans(rsample.matrix)
mean(sample.mean)
})
# output variance of sample mean
output$output_var <- renderText({
sample.mean <- rowMeans(rsample.matrix)
var(sample.mean)
})
# output histogram of sample mean
output$output_hist <- renderPlot({
sample.mean <- rowMeans(rsample.matrix)
ggplot(data.frame(sample.mean), aes(x = sample.mean)) +
geom_histogram(bins = input$bins)
})
})
shinyApp(ui = ui, server = server)
(1) The above codes are to create a shiny application to simulate random sample and verify Central Limit Theorem. However, since I just learned shiny, I have no idea where it is wrong.
(2) Also, if I want to change the parameter of a specific distribution based on the distribution selected by the user, what should I do?
The error returned from Rstudio is as follows:
Warning: Error in .getReactiveEnvironment()$currentContext: Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)
Stack trace (innermost first):
49: .getReactiveEnvironment()$currentContext
48: .subset2(x, "impl")$get
47: $.reactivevalues
46: $ [#4]
45: server [#4]
4: <Anonymous>
3: do.call
2: print.shiny.appobj
1: <Promise>
Error in .getReactiveEnvironment()$currentContext() :
Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)

The error says that code should be within a reactive or an observe statement. Have a look how I wrapped and used the variables
library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
titlePanel("Central Limit Theorem Simulation"),
sidebarLayout(
sidebarPanel(
numericInput("sample.size", "Size of each random sample",
value = 30, min = 1, max = 100, step = 1),
sliderInput("simulation", "THe number of simulation",
value = 100, min = 100, max = 1000, step = 1),
selectInput("sample.dist", "Population Distribution where each sample is from",
choices = c("Binomial","Poisson", "Normal", "Uniform") ),
numericInput("bins", "Number of bins in the histogram",
value = 20, min = 1, max = 50, step = 1),
submitButton(text = "Submit")
),
mainPanel(
h3('Illustrating outputs'),
h4('mean of random sample mean'),
textOutput(outputId = "output_mean" ),
h4('variance of random sample mean'),
textOutput(outputId = "output_var"),
h4("Table"),
tableOutput(outputId = "output_table"),
h4('histogram of random normal sample'),
plotOutput(outputId = "output_hist")
)
)
))
server <- shinyServer(function(input, output) {
# Return the random sample
rsample <- reactive({
ifelse(
input$sample.dist == "Binomial", rbinom(input$sample.size * input$simulation, 1, 0.5),
ifelse(input$sample.dist == "Poisson", rpois(input$sample.size * input$simulation, 1),
ifelse(input$sample.dist == "Normal", rnorm(input$sample.size * input$simulation),
runif(input$sample.size * input$simulation) ) ) )
})
# Return the random sample matrix
rsamplematrix <- reactive({
matrix(rsample(), nrow = input$simulation)
})
# output mean of sample mean
output$output_mean <- renderText({
sample.mean <- rowMeans(rsamplematrix())
mean(sample.mean)
})
# output variance of sample mean
output$output_var <- renderText({
sample.mean <- rowMeans(rsamplematrix())
var(sample.mean)
})
# output histogram of sample mean
output$output_hist <- renderPlot({
sample.mean <- rowMeans(rsamplematrix())
ggplot(data.frame(sample.mean), aes(x = sample.mean)) +
geom_histogram(bins = input$bins)
})
})
shinyApp(ui = ui, server = server)

Related

how to update a dataset in R shiny

Can I get help on how to get the below code to work? I am looking to update the numbers in
dataExample <- getDataset(n1 = c(20),n2 = c(20), means1 = c(18), means2 = c(9),stds1 = c(14), stds2 = c(14))
based on input values and then generate the plot whenever I apply changes but not sure how to do it. I read it somewhere it says need to use reactive or observe but I am not sure how to modify the code?
library(shiny)
library(plyr)
library(rmarkdown)
library(rpact)
design <- getDesignGroupSequential(kMax = 2, alpha = 0.05, informationRates = c(0.5, 1), typeOfDesign = "WT", deltaWT = 0.5)
ui <- fluidPage(
titlePanel("Efficacy Monitoring Using Conditional Power"),
sidebarLayout(
sidebarPanel(
numericInput('nn1', 'Number of Subjects at Current stage (Active)', 20, min = 1, max = 100),
numericInput('nn2', 'Number of Subjects at Current stage (Control)', 20, min = 1, max = 100),
textInput('Mean1', 'Mean1',"18"),
textInput('Mean2', 'Mean2',"9"),
textInput('SD1', 'SD1',"14"),
textInput('SD2', 'SD2',"14"),
textInput('nPlanned', 'Additional Numbers Planned',"40"),
submitButton(text = 'Apply Changes')
),
# Main panel for displaying outputs ----
mainPanel(plotOutput("plot2")
)
)
)
server <- function(input,output){
dataExample <- getDataset(
n1 = c(20),
n2 = c(20),
means1 = c(18),
means2 = c(9),
stds1 = c(14),
stds2 = c(14)
)
stageResults <- getStageResults(design, dataExample,thetaH0 = 0)
output$plot2<-renderPlot(
plot(stageResults, nPlanned = c(as.numeric(input$nPlanned)), thetaRange = c(0, 20))
)
}
# Run the app ----
shinyApp(ui, server)
Use a reactive function and put the input values
library(shiny)
library(plyr)
library(rmarkdown)
library(rpact)
design <- getDesignGroupSequential(kMax = 2, alpha = 0.05, informationRates = c(0.5, 1), typeOfDesign = "WT", deltaWT = 0.5)
ui <- fluidPage(
titlePanel("Efficacy Monitoring Using Conditional Power"),
sidebarLayout(
sidebarPanel(
numericInput('nn1', 'Number of Subjects at Current stage (Active)', 20, min = 1, max = 100),
numericInput('nn2', 'Number of Subjects at Current stage (Control)', 20, min = 1, max = 100),
# WHY THE CHOICE OF textInput instead of numericInput ?
textInput('Mean1', 'Mean1',"18"),
textInput('Mean2', 'Mean2',"9"),
textInput('SD1', 'SD1',"14"),
textInput('SD2', 'SD2',"14"),
textInput('nPlanned', 'Additional Numbers Planned',"40"),
submitButton(text = 'Apply Changes')
),
# Main panel for displaying outputs ----
mainPanel(plotOutput("plot2")
)
)
)
server <- function(input,output){
# Use the input values in a reactive function
dataExample <- reactive({
getDataset(
n1 = input$nn1,
n2 = input$nn2,
means1 = as.numeric(input$Mean1),
means2 = as.numeric(input$Mean2),
stds1 = as.numeric(input$SD1),
stds2 = as.numeric(input$SD2)
)
})
output$plot2<-renderPlot({
stageResults <- getStageResults(design, dataExample(), thetaH0 = 0)
plot(stageResults, nPlanned = c(as.numeric(input$nPlanned)), thetaRange = c(0, 20))
})
}
# Run the app ----
shinyApp(ui, server)

How to add interactive textinput panel in R shiny

library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
titlePanel("Central Limit Theorem Simulation"),
sidebarLayout(
sidebarPanel(
numericInput("sample_size", "Size of each random sample\n(max: 100)",
value = 30, min = 1, max = 100, step = 1),
sliderInput("simulation", "THe number of simulation",
value = 100, min = 100, max = 1000, step = 1),
selectInput("sample_dist", "Population Distribution where each sample is from",
choices = c("Binomial","Poisson", "Normal", "Uniform") ),
numericInput("bins", "Number of bins in the histogram\n(max: 50)",
value = 20, min = 1, max = 50, step = 1),
submitButton(text = "Submit")
),
mainPanel(
tabsetPanel(type = "pills",
tabPanel("mean of random sample mean", br(),
textOutput(outputId = "output_mean")),
tabPanel("variance of random sample mean", br(),
textOutput(outputId = "output_var")),
tabPanel("summary table", br(),
tableOutput(outputId = "output_table")),
tabPanel("sample matrix", br(),
verbatimTextOutput(outputId = "output_sample")),
tabPanel("histogram of random normal sample", br(),
plotOutput(outputId = "output_hist"))
)
)
)
))
server <- shinyServer(function(input, output) {
# Return the random sample
rsample <- reactive({
if (input$sample_dist == "Binomial") {
rsample <- rbinom(input$sample_size * input$simulation, 1, 0.5)
} else if (input$sample_dist == "Poisson") {
rsample <- rpois(input$sample_size * input$simulation, 1)
} else if (input$sample_dist == "Normal") {
rsample <- rnorm(input$sample_size * input$simulation)
} else {
rsample <- runif(input$sample_size * input$simulation)
}
rsample
})
# Return the random sample matrix
rsamplematrix <- reactive({
matrix(rsample(), nrow = input$simulation)
})
# output mean of sample mean
output$output_mean <- renderText({
sample_mean <- rowMeans(rsamplematrix())
mean(sample_mean)
})
# output variance of sample mean
output$output_var <- renderText({
sample_mean <- rowMeans(rsamplematrix())
var(sample_mean)
})
# output summary table of sample mean
output$output_table <- renderTable({
sample_mean <- rowMeans(rsamplematrix())
data.frame(mean(sample_mean), var(sample_mean))
})
# output the first 5 rows and 5 columns of the sample matrix
output$output_sample <- renderPrint({
k = rsamplematrix()
k[1:5, 1:5]
})
# output histogram of sample mean
output$output_hist <- renderPlot({
sample_mean <- rowMeans(rsamplematrix())
ggplot(data.frame(sample_mean), aes(x = sample_mean, y = ..density..)) +
geom_histogram(bins = input$bins, fill = "steelblue", col = "white")
})
})
shinyApp(ui = ui, server = server)
The above code runs well. Suppose right now I want to add textinput of distribution parameters for each distribution (for example, p is parameter for Binomial distribution, mu and sigma are parameters for normal distribution). These parameters input pop out when I made a selection for sample distribution.
What should I do? Which function should I use?
If you want to keep the parameter inputs hidden unless a distribution is selected then I think you want a conditionalPanel.
For example:
conditionalPanel("!(output.plot)", textInput("size", "Size"))
This size input panel would only show when output$plot is not yet rendered.
In your case I think you can use an input in the same way.
conditionalPanel('input.sample_dist) != "Poisson"', textInput("parameter2", "Parameter 2"))
This would show parameter 2 only if Poisson is not selected.
You'll need to remove your submitButton to ensure the parameter fields update when you select a new distribution. Replace it with a generic actionButton if you want to keep the same function.
I'd also suggest using numericInput fields and setting the appropriate label, min, max and step with updateNumericInput for each case in the server function when sample_dist updates.

Delay Reaction in R shiny

library(shiny)
library(ggplot2)
ui <- shinyUI(fluidPage(
titlePanel("Central Limit Theorem Simulation"),
sidebarLayout(
sidebarPanel(
numericInput("sample_size", "Size of each random sample\n(max: 100)",
value = 30, min = 1, max = 100, step = 1),
sliderInput("simulation", "The number of simulation",
value = 100, min = 100, max = 1000, step = 1),
numericInput("bins", "Number of bins in the histogram\n(max: 50)",
value = 20, min = 1, max = 50, step = 1),
selectInput("sample_dist", "Population Distribution where each sample is from",
choices = c("Bernoulli","Poisson", "Normal", "Uniform") ),
conditionalPanel(condition = 'input.sample_dist == "Bernoulli"',
textInput("prob", "Parameter (p)") ),
conditionalPanel(condition = 'input.sample_dist == "Poisson"',
textInput("lambda", "Parameter (lambda)") ),
conditionalPanel(condition = 'input.sample_dist == "Normal"',
textInput("mu", "Parameter (mu)"),
textInput("sigma", "Parameter (sigma)") ),
conditionalPanel(condition = 'input.sample_dist == "Uniform"',
textInput("min_a", "Parameter (a)"),
textInput("max_b", "parameter (b)") ),
actionButton("update", "Update Simulation")
),
mainPanel(
tabsetPanel(type = "pills",
tabPanel("mean of random sample mean", br(),
textOutput(outputId = "output_mean")),
tabPanel("variance of random sample mean", br(),
textOutput(outputId = "output_var")),
tabPanel("summary table", br(),
tableOutput(outputId = "output_table")),
tabPanel("sample matrix", br(),
verbatimTextOutput(outputId = "output_sample")),
tabPanel("histogram of random normal sample", br(),
plotOutput(outputId = "output_hist"))
)
)
)
))
server <- shinyServer(function(input, output) {
# Return the random sample
rsample <- eventReactive(input$update, {
if (isolate(input$sample_dist == "Bernoulli") ) {
rsample <- isolate(rbinom(n = input$sample_size * input$simulation,
size = 1, as.numeric(input$prob) ) )
} else if (isolate(input$sample_dist == "Poisson") ) {
rsample <- isolate(rpois(n = input$sample_size * input$simulation,
as.numeric(input$lambda) ) )
} else if (isolate(input$sample_dist == "Normal") ) {
rsample <- isolate(rnorm(n = input$sample_size * input$simulation,
mean = as.numeric(input$mu), sd = as.numeric(input$sigma) ) )
} else {
rsample <- isolate(runif(n = input$sample_size * input$simulation,
min = as.numeric(input$min_a), max = as.numeric(input$max_b) ) )
}
rsample
})
# Return the random sample matrix
rsamplematrix <- reactive({
matrix(rsample(), nrow = isolate(input$simulation) )
})
# output mean of sample mean
output$output_mean <- renderText({
sample_mean <- rowMeans(rsamplematrix())
mean(sample_mean)
})
# output variance of sample mean
output$output_var <- renderText({
sample_mean <- rowMeans(rsamplematrix())
var(sample_mean)
})
# output summary table of sample mean
output$output_table <- renderTable({
sample_mean <- rowMeans(rsamplematrix())
data.frame(mean(sample_mean), var(sample_mean))
})
# output the first 5 rows and 5 columns of the sample matrix
output$output_sample <- renderPrint({
k = rsamplematrix()
k[1:5, 1:5]
})
# output histogram of sample mean
output$output_hist <- renderPlot({
sample_mean <- rowMeans(rsamplematrix())
ggplot(data.frame(sample_mean), aes(x = sample_mean, y = ..density..)) +
geom_histogram(bins = isolate(input$bins), fill = "steelblue", col = "white")
})
})
shinyApp(ui = ui, server = server)
The code runs well, but there is a little problem with respect to Delay Reaction.
Suppose I run the simulation of binomial distribution with parameter=0.5, then all output would be generated. Then I choose a different distribution (for instance, normal distribution), before I render values to the parameters and click action button, the histogram plot is becoming grey for around a second. t seems that the server function is running although there is no change at all after that second.
What I wish is that when the distribution choice is made, the reaction are supposed to be delayed. So the server function should not run unless the action Button is clicked.
How can I fix this?

Interdependent widgets in Shiny ui

I am running the current version of RStudio, R, and all R packages.
In the sample code below, my goal is to set the maximum value for the xcol and ycol so they are limited to the number of columns in the dataframe that is being plotted. The code below results in the error "object 'input' not found." I suspect the problem may be that I am making the widgets in the ui dependent, but that is a guess on my part. Is that the problem, and is there a strategy that I can use to get around it.
I reviewed posts that contained the same error, but couldn't find anything that answered my question (or didn't recognize when it was answered.) The closest posts to my issue were: R Shiny error: object input not found; R Shiny renderImage() does not recognize object 'input'; Error in eval: object 'input' not found in R Shiny app; Conditional initial values in shiny UI?
Here is some reproducible code with random data.
library(tidyverse)
library(cluster)
library(vegan)
library(shiny)
dta <- rnorm(100, mean = 0, sd = 1)
mat <- matrix(dta, nrow = 10)
dm <- daisy(mat, metric = "euclidean") %>% as.matrix()
server <- function(input, output) {
output$plot <- renderPlot({
nmds <- metaMDS(dm, distance = "euclidean", k = input$dim, trymax = 2000, autotransform = FALSE, noshare = FALSE, wascores = FALSE)
df <- nmds$points %>% as.data.frame()
plot(df[,input$xcol], df[,input$ycol])
}, height = 500, width = 500)
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("dim", "Number of dimensions", value = 2, min = 2, max = 12),
numericInput("xcol", "X column", value = 1, min = 1, max = input$dim),
numericInput("ycol", "Y column", value = 2, min = 1, max = input$dim)
),
mainPanel(
plotOutput("plot")
)
)
)
You can use updateNumericInput to modify the UI from the server:
# Modify ui to use initial max
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
numericInput("dim", "Number of dimensions", value = 2, min = 2, max = 12),
numericInput("xcol", "X column", value = 1, min = 1, max = 2),
numericInput("ycol", "Y column", value = 2, min = 1, max = 2)
),
mainPanel(
plotOutput("plot")
)
)
)
# Modify server to update max when dim changes
# (notice the session parameter needed for updateNumericInput)
server <- function(input, output, session) {
output$plot <- renderPlot({
if(input$xcol>input$dim)
updateNumericInput(session, "xcol", value=input$dim, max=input$dim)
else
updateNumericInput(session, "xcol", max=input$dim)
if(input$ycol>input$dim)
updateNumericInput(session, "ycol", value=input$dim, max=input$dim)
else
updateNumericInput(session, "ycol", max=input$dim)
nmds <- metaMDS(dm, distance = "euclidean", k = input$dim, trymax = 2000, autotransform = FALSE, noshare = FALSE, wascores = FALSE)
df <- nmds$points %>% as.data.frame()
plot(df[,min(input$dim,input$xcol)], df[,min(input$dim,input$ycol)])
}, height = 500, width = 500)
}

Table output of values Shiny

I am trying to generate a table/list in Shiny of the values sampled from a probability distribution ( a list of the sampled values in a table format). I'm new to coding so this is like a foreign language to me. There is probably a lot of errors in the code although I can get it to run just not show the table.
library(shiny)
ui <- fluidPage(
sidebarPanel(
selectInput("dis","Please Select Probability Distribution Type:",
choices = c("Normal")),
sliderInput("sampleSize","Please Select Sample Size:",
min = 0,max = 5000,value = 1000,step = 100),
sliderInput("bins","Please Select Number of Bins:",
min = 1,max = 50,value = 10),
numericInput("sampleMean","Please Enter Sample Mean:",
min = 0,max = 5000,value = 2500,step = 10),
numericInput("sampleSd","Please Enter Standard Deviation:",
min = 0,max = 5000,value = 2,step = 10)
),
fluidRow(
column(12,
dataTableOutput("table"))
),
mainPanel(
plotOutput("histogram")
)
)
server <- function(input, output){
output$histogram <- renderPlot({
distType <- input$dis
n <- input$sampleSize
bins <- seq(min(input$bins), max(input$bins), length.out = input$bins + 1)
if(distType=="Normal"){
randomVec <- rnorm(n,mean = as.numeric(input$sampleMean),sd=as.numeric(input$sampleSd))
}
hist(randomVec,breaks=input$bins,col="red")
})
output$table <- renderDataTable({
distType <- input$dis
n <- input$sampleSize
if(distType=="Normal"){
randomVec <- rnorm(n,mean = as.numeric(input$sampleMean),sd= as.numeric(input$sampleSd))
}
sample(randomVec,100,replace = TRUE)
})
}
shinyApp(ui = ui, server = server)
From ?renderDataTable :
Arguments
expr An expression that returns a data frame or a matrix.
So you can do this:
output$table <- renderDataTable({
distType <- input$dis
n <- input$sampleSize
if(distType=="Normal"){
randomVec <- rnorm(n,mean = as.numeric(input$sampleMean),sd= as.numeric(input$sampleSd))
}
data.frame(sample(randomVec,100,replace = TRUE))
})

Resources