Radio buttons with numerical inputs in conditional panels - r

I am trying to make a Shiny app to do calculations as in [this pape
There are 3 sorts of calculation,called "calcprior", "calcpval" and "calcFPR".
Which calculation is to be done is chosen by radioButton. Each calculation requires different inputs. The inputs are placed in conditionalPanels. The correct names appear in thec onditionalPanel, but the numerical values aren't passed to the server, e.g. input$pval does not have the value entered in the numericInput in the conditional panel.
In contrast the value of nsamp, needed for all 3 calculations, is passed correctly to the server.
I'm a beginner at Shiny, so I hope that someone can explain what's going wrong. Not being able to see the values of variables makes debugging a million times harder than in regular R.
sidebarLayout(
sidebarPanel(
radioButtons("calctype", "Choose calculation:",selected = "calcFPR",
choices = c(
"prior (for given FPR and P val)" = "calcprior",
"P value (for given FPR and prior)" = "calcpval",
"FPR (for given P value and prior)" = "calcFPR")),
conditionalPanel(
condition = "input.calctype == 'calcprior'",
numericInput("pval", label = h5("observed P value"), value = 0.05, min
= 0, max = 1),
numericInput("FPR", label = h5("false positive risk"), value = 0.05,
min = 0, max = 1)
),
conditionalPanel(
condition = "input.calctype == 'calcpval'",
numericInput("FPR", label = h5("false positive risk"), value = 0.05,
min = 0, max = 1),
numericInput("prior", label = h5("prior probability of real effect"),
value = 0.5, min = 0, max = 1)
),
conditionalPanel(
condition = "input.calctype == 'calcFPR'",
numericInput("pval",label = h5("observed P value"),value = 0.05, min =
0, max = 1),
numericInput("prior", label = h5("prior probability of real effect"),
value = 0.5, min = 0., max = 1.)
),
inputPanel(
numericInput("nsamp",label = h5("Number in each sample"), step = 1,
value = 16, min = 2)
),
mainPanel(
(I also need to work out how to use the calctype to direct the server to the appropriate block of R code.)

Here is a working example for you:
library(shiny)
ui <- fluidPage(
titlePanel("|Species Table"),
sidebarLayout(
sidebarPanel(
radioButtons("calctype", "Choose calculation:",selected = "calcFPR",
choices = c(
"prior (for given FPR and P val)" = "calcprior",
"P value (for given FPR and prior)" = "calcpval",
"FPR (for given P value and prior)" = "calcFPR")),
uiOutput("test1"),
uiOutput("test2"),
inputPanel(
numericInput("nsamp",label = h5("Number in each sample"), step = 1,
value = 16, min = 2)
)),
mainPanel(textOutput("text1"),
textOutput("text2"))
))
server <- function(input, output) {
test <- reactive({
if(input$calctype == 'calcprior'){
label1 <- paste("observed P value")
label2 <- paste("false positive risk")
}else if(input$calctype == 'calcpval'){
label1 <- paste("false positive risk")
label2 <- paste("prior probability of real effect")
}else{
label1 <- paste("observed P value")
label2 <- paste("prior probability of real effect")
}
list(label1 = label1, label2 = label2)
})
output$test1 <- renderUI({
numericInput("test1", label = h5(test()$label1), value = 0.05, min = 0, max = 1)
})
output$test2 <- renderUI({
numericInput("test2", label = h5(test()$label2), value = 0.05, min = 0, max = 1)
})
output$text1 <- renderText({
input$test1
})
output$text2 <- renderText({
input$test2
})
}
shinyApp(ui = ui, server = server)
you do not need so many conditionalPanels, i have noticed in your code that the only thing that changes is the label of numericInput according to choosen calculation type. Therefore in this case i have used if...else... statement in the server to change the label of two `numericInputs (test1 and test2) with choosen calculation type.
Furthermore i have printed out the output of the numericInput `s (text1 and text2) to show you that the user input is acctually passed to server and can be further used in the calculations.

Related

How do I make R Shiny react to slider changes, but not recalculate everything if I want to plot another part of solution

I am new to shiny (and just joined the Stack Overflow, so apologies if I'm not following all etiquette rules yet :) ), and although I have managed to get my code working, there is something that I just cannot get my head around. Below is a code that solves a system of two differential equations, with coefficients being selected using Shiny sliders, and in the main panel I am trying to select which of the two variables to plot. The problem is that since selection of the plotting variable is part of the "input", if I change a variable that I want to plot, this results in the recalculation of the whole thing. I have attached a short code illustrating this problem on the example of a small system, but in reality I have a really large system of ODEs that takes quite a lot of time to solve, so I really need to make sure that if the sliders with parameters are not changed, the system is only solved once, and I can then separately plot each of the variables without a time-consuming recalculation of the whole thing.
I have had a look at "reactive" as an option, but can't see how to make it work for this. Could you please have a look at the short code below and let me know if that's possible, and more specifically, how to make it plot either U or V but without solving the system again.
Thanks a lot in advance!
library(deSolve)
library(shiny)
library(shinyWidgets)
library(plotly)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(
column(width=6,
sliderInput("a", "Coef 1",0, 5, 1, step=0.2),
sliderInput("b", "Coef 2", 0, 5, 1, step=0.2)
)
)
),
mainPanel(
selectInput("Var",
label = "Choose variable to plot:",
choices = c("First"="U", "Second"="V"),
selected = c("U")
),
plotlyOutput("plot0")
)
)
)
LV=function(t,y,p){ # define Lotka-Volterra system
with(as.list(p),{
z=rep(0,2)
z[1]=y[1]-a*y[1]*y[2]
z[2]=b*y[1]*y[2]-y[2]
return(list(z))
})
}
Run_LV=function(p){ # run the simmulation
t = seq(from=0, to=10, by=0.1)
y0=c(1.5,0.7) # initial condition
para=c(list("a"=p$a,"b"=p$b)) # values of parameters
out = ode(y=y0, times=t, func=LV, parms=para ,method="ode45")
return(list("out"=out))
}
server <- function(input, output) {
output$plot0=renderPlot({
sim=Run_LV(input)
sol=sim$out
xvar=sol[,1] # time
if(input$Var=="U"){
yvar=sol[,2] # will plot U component
}else{
yvar=sol[,3] # will plot V component
}
data<- data.frame(xvar,yvar)
p=plot_ly(data,x=~xvar, y=~yvar, type = 'scatter', mode = 'lines')
p
})
}
shinyApp(ui = ui, server = server)
Here one of my Lotka-Volterra teaching apps implemented as Markdown document. I hope that it can serve as an example:
---
title: "Resource Dependent Lotka Volterra Model"
output: html_document
runtime: shiny
---
```{r, echo=FALSE}
suppressMessages(library(deSolve))
lv <- function (t, x, parms) {
with(as.list(c(x, parms)),{
ds <- s_in - b * s * p + g * k + pulse(t, s_start, s_duration, s_pulse)
dp <- c * s * p - d * k * p
dk <- e * p * k - f * k
list(c(ds, dp, dk))
})
}
#parms <- c(s_in=0, b=0, c=0.1, d=0.1, e=0.1, f=0.1, g=0, s_start=0, s_duration=0, s_pulse=0)
times <- seq(0, 200, by=0.2)
#init <- c(s=1, p=1, k=0.5)
pulse <- function(t, s_start, s_duration, h_pulse) {
if ((s_start <= t) & (t < (s_start + s_duration))) h_pulse else 0
}
```
```{r, echo = FALSE, }
simulate <- reactive({
parms <- c(s_in=input$s_in,
b=input$b, c=input$c, d=input$d, e=input$e, f=input$f, g=input$g,
s_start=input$s_start, s_duration=input$s_duration, s_pulse=input$s_pulse)
init <- c(s=input$S0, p=input$P0, k=input$K0)
ode(init, times, lv, parms, method="adams")
})
```
```{r, echo=FALSE}
renderPlot({
#print(system.time(
res <- simulate()
#))
par(lwd=2)
par(las=1)
par(cex.axis=1.4)
layout(matrix(c(1,2), nrow=1, byrow=TRUE), widths=c(2, 1))
matplot(res[,1], res[,2:4], type="l", xlab="time", col=c("black", "forestgreen", "red"), lwd=3, ylab="state variables")
legend("topright", legend=c("S", "P", "K"), col=c("black", "forestgreen", "red"), lwd=3, lty=1:3, cex=1.4)
plot(res[,3], res[,4], type="l", xlab="P", ylab="K")
})
```
<small>
```{r, echo=FALSE}
inputPanel(flowLayout(
h4("Initial values:"),
numericInput(
"S0", label = "S0: Substrate", value = 1.0, min = 0, max = 2, step = 0.1
),
numericInput(
"P0", label = "P0: Producer", value = 1.0, min = 0, max = 2, step = 0.1
),
numericInput(
"K0", label = "K0: Consumer", value = 0.5, min = 0, max = 2, step = 0.1
)),
flowLayout(
h4("Model parameters:"),
numericInput(
"b", label = "b: substrate utilisation", value = 0.0, min = 0, max = 1, step = 0.01
),
numericInput(
"c", label = "c: producer growth", value = 0.1, min = 0, max = 1, step = 0.1
),
numericInput(
"d", label = "d: predation loss", value = 0.1, min = 0, max = 1, step = 0.1
),
numericInput(
"e", label = "e: consumer growth", value = 0.1, min = 0, max = 1, step = 0.1
),
numericInput(
"f", label = "f: consumer mortality", value = 0.1, min = 0, max = 1, step = 0.1
),
numericInput(
"g", label = "g: substrate recycling", value = 0.0, min = 0, max = 1, step = 0.01
)),
flowLayout(
h4("Substrate import:"),
numericInput(
"s_in", label = "S_in (import baselevel)", value = 0.0, min = 0, max = 1, step = 0.01
),
sliderInput(
"s_pulse", label = "s_pulse (pulse height):", min = 0.0, max = 1.0, value = 0, step = 0.1
),
sliderInput(
"s_start", label = "s_start (time of pulse):",min = 0.0, max = max(times), value = 10, step = 1
),
sliderInput(
"s_duration", label = "s_duration (duration):", min = 0.0, max = 5, value = 1, step = 0.1
)
), textsize="50%")
```
</small>
### 3D State diagram
```{r, echo=FALSE}
library(scatterplot3d)
renderPlot({
res <- simulate()
scatterplot3d(res[,2], res[,3], res[,4], type="l", xlab="S", ylab="P", zlab="K", color="red", lwd=2)
}, width=600, height=400)
```

How to feed a value from an output object as an input into another output object?

I'm working on a simulation-based app. I have 2 initial numeric input objects, "max imp count" and "population size". Based on what is fed into these numeric input objects, the app generates 2 more input objects (really as output objects)- "select_proportion" and "select_probability". If the "max imp count" is 3, the app should generate 8 new input objects- 4 which ask for proportion (proportion0, proportion1, proportion2, proportion3), and 4 of which ask for probability0, probability1, probability2 and probability3. I want to feed these proportion and probability values into sample functions that work in the following manner:
1) sample(c(0,input$max_imp, 1), size=input$population, replace=TRUE, prob= these take the proportion values
sample for binary values for all proportion brackets:
2) sample(c(0,1), length(proportion_i), replace=TRUE, prob=these take the probability values)
Ideally, I would like to have this all in a dataframe where I have columns for which proportion bracket a record belongs to and whether they have 0 or 1.
Code:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Simulation"),
dashboardSidebar(
sidebarMenu(
numericInput("max_imp", "max imp count", 0, min = 0, max = 15, step = 1),
numericInput("population", "population size", 1, min = 0, max = 100000, step = 1),
menuItemOutput("menuitem")
)
),
dashboardBody(
uiOutput("select_proportion"),
uiOutput("select_probability")
))
server <- function(input, output) {
output$select_proportion = renderUI(
lapply(0:(input$max_imp), function(i){
numericInput(inputId = "i1", label = paste0("proportion",i), 0, min = 0, max = 1, step = 0.05)}))
output$select_probability = renderUI(
lapply(0:(input$max_imp), function(i){
numericInput(inputId = "i2", label = paste0("probability",i), 0, min = 0, max = 1, step = 0.05)}))
}
# Run the application
shinyApp(ui = ui, server = server)
Your output elements are only UI container which are then filled with the input elements defined in the renderUI functions. You can easily access the values of these input elements as you do it with your other inputs.
The only thing here is that you have to set the IDs of the inputs in a dynamic way e.g. instead of id = "i2" for the second input use id = paste("input", i, "2", sep = "-"). This will create you input$max_imp + 1 different inputs. The values can then be accessed via input$input_1_2.
BR
Sebastian

Shiny save as pdf or plot

Here is my code I have 3 different questions, I searched evrywhere and tryied sooo many things, but it always gave me an error .
First how can I add a function to save my rglwidgetoutput to any file ?
And also mby save the log .
Secound: If I open the program it always opens a small "focus" window, can I somehow remove that ?
And last but not least, I have a Log , and I want to rename the data_planes so the logfile looks better :)
#######################################################################################
# Install librarys #
#######################################################################################
#install.packages("shiny")
#install.packages("rgl")
#install.packages("shinythemes")
#install.packages("devtools")
library(shiny)
library(rgl)
library(shinythemes)
library(devtools)
#install_github("rgl", "trestletech", "js-class")
#install_github("rgl", "trestletech", "js-class")
#######################################################################################
# User Interface #
#######################################################################################
ui <- fluidPage(theme = shinytheme("slate"),
headerPanel("Block Theory"),
sidebarPanel(
numericInput(inputId = "dd", label = "Dip direction:", value = "", width = "80%", min = 0, max = 360),
numericInput(inputId = "fa", label = "Fracture angle:", value = "", width = "80%", min = 0, max = 90),
numericInput(inputId = "position_x", label = "Position:", value = "", width = "40%"),
numericInput(inputId = "position_y", label = "", value = "", width = "40%"),
numericInput(inputId = "position_z", label = "", value = "", width = "40%"),
#selectInput("form", "Form:",
# c("Circle", "Square", "Ellipsoid")),
actionButton(inputId = "add", label = "Add a plane"),
actionButton(inputId = "plotbutton", label = "Update")
),
mainPanel(
tabsetPanel(
tabPanel("Plot", rglwidgetOutput(outputId = "plot")), # Output
tabPanel("Log", verbatimTextOutput(outputId = "log_planes")), # Log File
# OPTIONS :
tabPanel("Preferences",
checkboxInput("axes_lim", "axes min / max"),
conditionalPanel(
condition = "input.axes_lim == true",
splitLayout(
numericInput(inputId = "min_x", label = "x min:", value = "0", width = "90%"),
numericInput(inputId = "max_x", label = "x max:", value = "1000", width = "90%")),
splitLayout(
numericInput(inputId = "min_y", label = "y min:", value = "0", width = "90%"),
numericInput(inputId = "max_y", label = "y max:", value = "1000", width = "90%")),
splitLayout(
numericInput(inputId = "min_z", label = "z min:", value = "0", width = "90%"),
numericInput(inputId = "max_z", label = "z max:", value = "1000", width = "90%"))),
checkboxInput("axes", "Change axes ratio"),
conditionalPanel(
condition = "input.axes == true",
sliderInput("x_axis", "x axis:",min = 0, max = 1, value = 1, step = 0.1),
sliderInput("y_axis", "y axis:",min = 0, max = 1, value = 1, step = 0.1),
sliderInput("z_axis", "z axis:",min = 0, max = 1, value = 1, step = 0.1)),
checkboxInput("theme", "Change shiny theme"),
conditionalPanel(
condition = "input.theme == true",
shinythemes::themeSelector() )
))
) # /Main panel
) # /ui
#######################################################################################
# SERVER #
#######################################################################################
server <- function(input, output) {
data_planes <- data.frame()
makeReactiveBinding("data_planes")
observe({
input$add
isolate({
data_planes <<- rbind(data_planes, data.frame(input$dd, input$fa , input$position_x , input$position_y , input$position_z))
data_planes <<- na.omit(data_planes)
})
})
output$plot <- renderRglwidget({
input$plotbutton
isolate({
####################################################
# Open 3d plot:
x<-sample(input$min_x:input$max_x, 100)
y<-sample(input$min_y:input$max_y, 100)
z<-sample(input$min_z:input$max_z, 100)
plot3d(x, y, z, type = "n",xlim = c(min(x), max(x)), ylim = c(min(y), max(y)), zlim = c(min(z), max(z),expand = 1.03))
aspect3d(input$x_axis , input$y_axis , input$z_axis)
####################################################
i=1;
while (i <= nrow(data_planes)) {
phi <- data_planes[i,1] * pi / 180
theta <- data_planes[i,2] * pi / 180
Px <- data_planes[i,3]
Py <- data_planes[i,4]
Pz <- data_planes[i,5]
n <- c(sin(theta)*sin(phi), sin(theta) * cos(phi), cos(theta))
# n <- c(-sin(theta)*sin(phi), sin(theta) * cos(phi), -cos(theta))
P_n <- cos(phi)*sin(theta)*Px+(sin(phi)*sin(theta))*Py+cos(phi)*Pz # d = -P * n
# planes3d() plots equation: a*x + b*y + c*z + d = 0
a <- -sin(theta)*sin(phi)
b <- sin(theta) * cos(phi)
c <- -cos(theta)
d <- P_n
cols<-rgb(runif(5),runif(5),runif(5)) #random color genarator
i <- i + 1
planes3d(a, b, c , d , col = cols, alpha = 0.6)
}
rglwidget() # opens the plot inside of main panel
})
})
output$log_planes <- renderPrint(data_planes)
}
#######################################################################################
shinyApp(ui = ui, server = server
)
It's not easy to save rgl output to a PDF. You can save it to an html page using code like this:
htmlwidgets::saveWidget(rglwidget(), file = "rgl.html")
This will fail if it can't find Pandoc; you can use
htmlwidgets::saveWidget(rglwidget(), file = "rgl.html", selfcontained = FALSE)
without Pandoc, but it will create both the HTML file and a subdir of supporting files.
The little window you're seeing is probably the rgl output window. If you never want to see that, run
options(rgl.useNULL = TRUE)
before loading the rgl package. This is a good idea on a Shiny app, because they may be running on a server somewhere and you don't want to try to open an rgl window there.
Sorry, I don't really understand your third question.

eventReactive, source() and plotting on R Shiny

I am having some trouble with creating plots on eventReactive. I have a source code for inside event reactive, and I am trying to make multiple plots. I am a little unsure how to make multiple plots, so I tried to make one into a plot. However, I am still having trouble with this.
My ui and server are
library(shiny)
library(lpSolve)
ui <- fluidPage(
mainPanel(
tabsetPanel(
tabPanel("Information required for the model",
sliderInput("Reservoirs", label = h3("Total Number of Reservoirs"),
min = 1, max = 25,
value = 10),
sliderInput("Municipalities", label = h3("Total Number of Municipalities Served by the Reservoirs"),
min = 1, max = 150,
value = 15),
sliderInput("Time", label = h3("Total Number of Months for Future Decision"),
min = 0, max = 60,
value = 0)
),
tabPanel("Summary of csv files",
actionButton("Run_Model", "Run Model")),
tabPanel("Results",
plotOutput("plot_ipsita"),
img(outfile)
)
)))
server <- function(input, output) {
running_code<-eventReactive(input$Run_Model, {
source("Source_code.R", local=TRUE)
outfile <- tempfile(fileext = '.png')
png(outfile,width=30,height=nR*3,units = "in",res=200)
par(mfrow=c(ceiling(nR)/2, 2))
for (i in 1:nR){
hist(abcd[i,1,1])
}
dev.off()
plot((colSums(abcd[1,,])),type="l",ylab="Withdrawal [mio m3]",xlab = "months",col=1,lwd=3,lty=1)
abline(h=130, col = 2,lwd=3,lty=3)
abline(h=205, col=3, lwd=3,lty=4)
legend("topleft", c("","All Reservoirs","Import","Failure"), col = c(0,1,2,3),pt.cex=0.5,lty=1:4,lwd=3, cex=0.75,bty="n")
title(paste0("Withdrawals from reservoirs and imports and failure for % initial storage" ), cex.main=1)
})
output$plot_ipsita <- renderPlot({
running_code()
})
}
shinyApp(ui = ui, server = server)
And my source code is
nR<-input$Reservoirs
nM<-input$Municipalities
nT<-input$Time
abcd<-array(data=0, c(nR,nM,nT))
for (i in 1:nR){
abcd[i,,]<-(1+i)*55
}
My actual code is a lot more complicated, so I tried to simplify it to test with this one, and it does not seem happy. Nothing is running. However, if I try to run it as a regular R code, I am able to get all the results.
Please help!!!
The mistake in your code is in your ui where your sliderInput Time has a default value 0. This causes the following loop to fail not assigning any value to array abcd:
for (i in 1:nR){
abcd[i,,]<-(1+i)*55
}
Hence, colSums(abcd[1,,]) dos not have the value due to which it fails.
If you change the sliderInput("Time", label = h3("Total Number of Months for Future Decision"), min = 0, max = 60, value = 0) to sliderInput("Time", label = h3("Total Number of Months for Future Decision"), min = 0, max = 60, value = 2) your code creates a graph as follows:
Hope it helps!

Dynamic update of a label withMathJax in Shiny UI

I'm using shiny::updateSliderInput to update the label of a slider. I would like the label for the slider to render with the Greek character xi (ξ) and a subscript. The subscript is target of the updateSliderInput call.
I've been successful generating the label without the updateSliderInput call, but correctly using the withMathJax() call for the label update has not worked as well as I would prefer.
A reproducible example of a shiny app for this issue is:
library(shiny)
shinyApp(ui = shinyUI(fluidPage(sliderInput("order", withMathJax("Order, \\(k\\)"), min = 3, max = 7, value = 4, step = 1),
sliderInput("iknots", "iKnots", min = 0, max = 10, value = 5, step = 1),
sliderInput("xi1", withMathJax(), min = 0, max = 10, value = 1, step = 0.1))),
server = shinyServer(function(input, output, clientData, session) {
observe({
k <- as.integer(input$order)
l <- as.integer(input$iknots)
updateSliderInput(session, "xi1", label = paste0("\\(\\xi_{", k + l, "}\\)"))
})
}))
Upon initial loading of the app in browser we have a the desirable label, the ξ9 is correct.
After adjusting either of the first two sliders, the label for the third slider does not render as expected.
I've tried using withMathJax in label argument of updateSliderInput but have had undesirable labels. Changing the updateSliderInput line in the above to
updateSliderInput(session, "xi1", label = withMathJax(paste0("\\(\\xi_{", k + l, "}\\)")))
and setting the sliderInput to have the either label = withMathJax() or label = "" results in the initial label of
and updated label of
How can the subscript on the ξ be correctly updated in the slider label?
You might need to use renderUI and uiOutput to create the last slider otherwise the javascript used to display the MathJax is not called when you update the label.
You could do:
library(shiny)
shinyApp(ui = shinyUI(fluidPage(sliderInput("order", withMathJax("Order, \\(k\\)"), min = 3, max = 7, value = 4, step = 1),
sliderInput("iknots", "iKnots", min = 0, max = 10, value = 5, step = 1),
uiOutput("lastSlider"))),
server = shinyServer(function(input, output, clientData, session) {
output$lastSlider<- renderUI({
k <- as.integer(input$order)
l <- as.integer(input$iknots)
sliderInput("xi1",label = withMathJax(paste0("\\(\\xi_{", k + l, "}\\)")), min = 0, max = 10, step = 0.1,value=input$xi1)
})
}))

Resources