r Shiny action button and data table output last N rows - r

I need help with action button working only once. If you click on button it will shows you graph,table and some text. But if you want to change something on sidebar like a colour it will change and you dont have to press the button... (I need to have: If you want to change something colour,values..you need to always push the action button to confirm it it cant change without button)
Also, I need to show only the last N rows from table airquality which depends on numericID input. Can anyone help me?
library(shiny)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
observeEvent(input$gobutton, {
output$textik <- renderText({
vypis=c("Zobrazili ste tabuľku s", input$numericID, "riadkami a boxplot pre atribút Ozone ste nastavili na farbu ", input$radioID)
print(vypis)
})
output$table <- renderTable(airquality)
output$distPlot <- renderPlot({
x <- airquality[,input$selectID]
boxplot(x~airquality$Month, col = input$radioID, border = 'white', main=input$textID)
})
})
})
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Dáta Airquality"),
# Sidebar with a slider input for number of bins
sidebarPanel(
numericInput("numericID","PoÄet riadkov tabuľky",value=6, min=1, max=100, step=5),
selectInput("selectID","Vyberte atribút",choices=c(colnames(airquality))),
radioButtons("radioID","Vyberte farbu grafu", choices=c("yellow","green")),
textInput("textID","Zadajte nadpis grafu", value ="Nadpis"),
actionButton("gobutton","Start")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot"),
tableOutput("table"),
textOutput("textik")
)
))

#Tomáš - I would recommend avoiding putting your output statements inside of observeEvent. Instead, I would create an eventReactive that will be triggered by your action button. And when this happens, it will store all your needed info in a list, and all of your outputs will be dependent on this list. Here is one way to do this (below is the server function only).
server <- function(input, output) {
aq_data <- eventReactive(input$gobutton, {
list(data = airquality, nID = input$numericID, rID = input$radioID, sID = input$selectID, tID = input$textID)
})
output$textik <- renderText({
vypis=c("Zobrazili ste tabuľku s", aq_data()[["nID"]], "riadkami a boxplot pre atribút Ozone ste nastavili na farbu ", aq_data()[["rID"]])
print(vypis)
})
output$table <- renderTable(tail(aq_data()[["data"]], aq_data()[["nID"]]))
output$distPlot <- renderPlot({
dat <- aq_data()
boxplot(reformulate("Month", dat[["sID"]]), col = dat[["rID"]], border = 'white', main = dat[["tID"]], data = dat[["data"]])
})
}

Related

Click Interactive Plot in R Shiny

I'm trying to create a plot with a bunch of boxes and then when a box gets clicked on it gets colored in up. I'm having two issues with this. 1. I can't figure out a way for the figure to update dynamically when I click. 2. I can't figure out how to store the values that come out of the click input variable so that I have stored all previous clicks and would be able to color in multiple boxes. You can see a few ways I've tried to solve and test either of the two issues and I'm not having any luck. Any help with either issue would be appreciated.
ui <- fluidPage(
# Application title
titlePanel("Boxes"),
sidebarLayout(
sidebarPanel(
textOutput("text")),
# Get it it's a pun
mainPanel(
plotOutput("boxPlot",click = "test")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
vals <- reactiveValues(x=NA,y=NA,test=NA)
observeEvent(input$click, {
vals$x <- c(vals$x,input$test$x)
vals$y <- c(vals$y,input$test$y)
vals$test <- input$test$x
})
output$boxPlot <- renderPlot({
par(mai=c(0,0,0,0))
plot(1,ylim=c(2,15),xlim=c(2,15),type='n',yaxs='i',xaxs='i',ylab='',xlab='',axes=F)
for (i in 2:15) {
abline(v=i)
abline(h=i)
}
observeEvent(input$click, { rect(floor(input$test$x),floor(input$test$y),ceiling(input$test$x),ceiling(input$test$y),col='blue')})
# if (length(vals$x) > 0) {
# rect(floor(vals$x[1]),floor(vals$y[1]),ceiling(vals$x[1]),ceiling(vals$y[1]),col='blue')
# }
})
# output$text <- renderText(vals$x[length(vals$x)])
output$text <- renderText(vals$test)
}
# Run the application
shinyApp(ui = ui, server = server)
This might be a simple solution.
You should only have one single observeEvent for your click event. In that observeEvent, store your x and y values as reactiveValues as you current are doing.
Then, your renderPlot should plot the grid lines and filled in rectangles based on your reactiveValues. By including input$boxPlot_click (as I called it) in renderPlot the plot will be redrawn each click.
library(shiny)
ui <- fluidPage(
titlePanel("Boxes"),
sidebarLayout(
sidebarPanel(
textOutput("text")),
mainPanel(
plotOutput("boxPlot", click = "boxPlot_click")
)
)
)
server <- function(input, output) {
vals <- reactiveValues(x=NA,y=NA)
observeEvent(input$boxPlot_click, {
vals$x <- c(vals$x,input$boxPlot_click$x)
vals$y <- c(vals$y,input$boxPlot_click$y)
})
output$boxPlot <- renderPlot({
input$boxPlot_click
par(mai=c(0,0,0,0))
plot(1,ylim=c(2,15),xlim=c(2,15),type='n',yaxs='i',xaxs='i',ylab='',xlab='',axes=F)
for (i in 2:15) {
abline(v=i)
abline(h=i)
}
for (i in seq_along(length(vals$x))) {
rect(floor(vals$x),floor(vals$y),ceiling(vals$x),ceiling(vals$y),col='blue')
}
})
output$text <- renderText(paste0(vals$x, ', ' , vals$y, '\n'))
}
shinyApp(ui = ui, server = server)

Subsetting dataframe based on dynamically generated checkBoxGroupInput: checkbox keeps resetting

I would like to use a Shiny app to load a file (tab-separated), dynamically create a checkboxGroupInput, after the loading of the file (using observeEvent) using the column headers, then subset the data frame that comes from the file based on the selected checkboxes. The data is then plotted using code I can't share right now.
All is working fine, apart from the last bit: subsetting the dataframe based on the selected checkboxes in checkboxGroupInput. The checkboxes all start selected, and the plot is created fine. If you un-select one of the checkboxes, the plot re-plots appropriately for a split second (so the subsetting is working fine) then the unselected checkbox re-selects itself and the plot goes back to the old plot.
This is the tiny problem I'm trying to solve, guessing it's one line of code. I'm assuming it's because of some reactivity that I don't understand and the checkbox constantly resetting itself.
Here is an example:
###
## Some functions I can't share
### Shiny app
library(shiny)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("MagicPlotter"),
# Sidebar
sidebarLayout(
sidebarPanel(
fileInput(inputId = "myInputID",
label = "Your .csv file",
placeholder = "File not uploaded"),
uiOutput("mylist"),
uiOutput("submitbutton")
),
# Show a plot
mainPanel(
verticalLayout(
plotOutput("myPlot"))
)
)
)
# Define server
server <- function(input, output) {
output$myPlot <- renderPlot({
inputfile <- input$myInputID
if(is.null(inputfile))
{return()}
mydataframe <- read.table(file=inputfile$datapath, sep="\t", head=T, row.names = 1)
mydataframecolumnnames <- colnames(mydataframe[1:(length(mydataframe)-1)])
# the last column is dropped because it's not relevant as a column name
observeEvent(input$myInputID, {
output$mylist <- renderUI({
checkboxGroupInput(inputId="mylist",
label="List of things to select",
choices=mydataframecolumnnames,
selected=mydataframecolumnnames)
})
})
observeEvent(input$myInputID, {
output$submitbutton <- renderUI({
submitButton("Subset")
})
})
mysubset <- mydataframe[input$mylist]
myPlot(mysubset)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Thanks all
I think there are a few things that might help...
One, you can move your observeEvent methods outside of your renderPlot.
Also, you can create a reactive function to read in the data table.
I hope this helps.
server <- function(input, output) {
myDataFrame <- reactive({
inputfile <- input$myInputID
if(is.null(inputfile))
{return()}
read.table(file=inputfile$datapath, sep="\t", head=T, row.names = 1)
})
output$myPlot <- renderPlot({
req(input$mylist)
mysubset <- myDataFrame()[input$mylist]
plot(mysubset)
})
observeEvent(input$myInputID, {
mydata <- myDataFrame()
mydataframecolumnnames <- colnames(mydata[1:(length(mydata)-1)])
output$mylist <- renderUI({
checkboxGroupInput(inputId="mylist",
label="List of things to select",
choices=mydataframecolumnnames,
selected=mydataframecolumnnames)
})
})
observeEvent(input$myInputID, {
output$submitbutton <- renderUI({
submitButton("Subset")
})
})
}

R Shiny stop for user input and display all plots

I have a script which I want to add to my Shiny app, and the original script can be simplified to the following:
plot(c(1:3),c(2,4,6), main ="This is first plot I want displayed")
a <- menu(c(1:5), title="what would you like to change the first point to?")
plot(c(1:3),c(a,4,6), main ="This is second plot I want displayed")
b <- menu(c(1:5), title="what would you like to change the second point to?")
plot(c(1:3),c(a,b,6), main ="This is second plot I want displayed")
The above script plots the first plot, then waits for user input before plotting second, and waits again for user input before plotting third.
However, when I try to convert it to shiny app as seen below, it never updates the first or the second plot, and the things I've tried to make it stop for user input where shown have not worked.
I have tried using req() but it seems to stop the script entirely so the last things are not run at all, and you have to start the entire script over.
So, how can i make it display all plots in sequence, and how can I make the script stop and wait for input before continuing?
if(interactive()){
ui <- fluidPage(
actionButton("button","Click me"),
selectInput("input", "Input", c(1:10)),
textOutput("text"),
plotOutput("plot")
)
server <- function(input, output) {
a<-1
observeEvent(input$button, {
output$plot <- renderPlot(plot(c(1:3),c(2,4,6), main ="This is first plot I want displayed"))
output$text <- renderText("Please select a number to multiply the first point with")
#This is where I want the script to wait for user input
output$plot <- renderPlot(plot(c((1),(2),(3)),c((input$input),(a),(3)), main="This is plot the second plot"))
a<-a+1
#Here I want the script to wait for user input again
output$plot <- renderPlot(plot(c((1),(2),(3)),c((input$input),(a),(3)), main="This is plot the third plot"))
})
}
shinyApp(ui=ui, server=server)
}
The goal is that it updates the plots when they are rendered in the code, and that it waits for user input until script continues, instead of just keeping going.
Perhaps this is what you want.
req is used to only display when a variable is available. You need to create the second renderUI in the server since you cannot use req in the ui part.
if(interactive()){
ui <- fluidPage(
plotOutput("plot1"),
numericInput ("num1", "Please select a number to multiply the first point with", NA, 1, 10),
plotOutput("plot2"),
uiOutput("num2"),
plotOutput("plot3")
)
server <- function(input, output) {
output$plot1 <- renderPlot(plot(c(1:3),c(2,4,6), main ="This is first plot I want displayed"))
output$plot2 <- renderPlot({
req(input$num1)
plot(c(1:3),c(2*(input$num1),4,(6)),
main="This is plot the second plot"
)
}
)
output$plot3 <- renderPlot({
req(input$num1, input$num2)
plot(c(1:3),c(2*(input$num1)+(input$num2),4,(6)),
main="This is plot the third plot"
)
}
)
output$num2 <- renderUI({
req(input$num1)
numericInput ("num2", "Please select a number to add to first point", NA, 1, 10)
})
}
shinyApp(ui=ui, server=server)
}
To be honest, I´m not 100% sure if I know what you expect, even after reading your text 5 times. I have a guess ;-).
Your pause function, which cause plots to render one step after another can be done with invalidateLater. This has to "live" inside a reactiveValue. I don´t know exactly who is the creator of this function, I saved it in my snippets (all glory to the unknown person).
To render a plot or run a script based on the input of a user, try to catch it by using an if statement.
Hope this helps :-).
library(shiny)
if(interactive()){
ui <- fluidPage(
selectInput("input", "Input", c(1:10)),
actionButton("apply", "Apply"),
textOutput("text"),
plotOutput("plot")
)
server <- function(input, output, session) {
rv <- reactiveValues(i = 0)
maxIter <- 10
observeEvent(input$apply, {
rv$i <- 0
observe({
isolate({
rv$i <- rv$i + 1
})
if (isolate(rv$i) < maxIter){
invalidateLater(2000, session)
}
})
})
output$plot <- renderPlot( {
if(rv$i > 0) {
if(input$input <= 4) {
plot(c((rv$i*1),(rv$i*2),(rv$i*3)),c((1),(2),(3)), main = sprintf("Input <= 4; Round %i", rv$i), type = "l")
} else {
plot(c((rv$i*1),(rv$i*5),(rv$i*4)),c((1),(2),(3)), main = sprintf("Input > 4; Round %i", rv$i), type = "l")
}
} else {
plot(c(1:3),c(2,4,6), main ="This is first plot")
}
})
}
shinyApp(ui=ui, server=server)
}

Return reactive output from user-defined function in shiny

I am relatively new to shiny. I created an NBA win-probability model a few weeks ago and have been trying to create a shiny app that will generate the output from my model for which I have created a user-defined function.
In my user interface I want a place to enter numeric input value for "Home Points", "Away Points", and "Time Remaining". Once, values have been entered for these values I want the user to click an action button. After the action button is clicked I simply want the app to display the output from my function in the main panel. However, I am unable to figure out how to get this to work.
Here is my code:
library(shiny)
# Define UI for application that calculates win probability
ui <- fluidPage(
# Application title
titlePanel("Win Probability"),
# Sidebar layout with inputs and output definitions
sidebarLayout(
#sidebar panel for inputs
sidebarPanel(
#Add numeric input for home team points
numericInput(inputId = "home.pts", label = h3("Home Points"), value = 0),
#Add numeric input for away team points
numericInput(inputId = "away.pts", label = h3("Away Points"), value = 0),
#Add numeric input for time remaining in fourth quarter
numericInput(inputId = "time", label = h3("Time Remaining"), value = 0),
#Add action buttion
actionButton("goButton","Apply")),
# Show output
mainPanel(
verbatimTextOutput("win_prob")
)))
win_prob <- function(time, home.pts, away.pts) {
#calculate point difference
diff <- home.pts - away.pts
#Store intercept and betas
intercept <- 0.09564935
b_time <- 0.01087832
b_diff <- 0.5243092
b_interact <- -0.03066952
#calculate and store logit
logit <- intercept + (time*b_time) + (diff*b_diff) +
((time*diff)*b_interact)
#function to change logit to probability
logit2prob <- function(logit) {
odds <- exp(logit)
prob <- odds/(1+odds)
}
#Store probability
prob <- logit2prob(logit)
prob
}
# Define server to return win probability
server <- function(input, output) {
#Store reactive values
home.pts <- reactive({input$home.pts})
away.pts <- reactive({input$away.pts})
time <- reactive({input$time})
output$win_prob <- renderPrint({win_prob(reactive({input$home.pts}),
reactive({input$away.pts}), reactive({input$time}))})
}
# Run the application
shinyApp(ui = ui, server = server)
If someone can please help me I would greatly appreciate it!
Thank you!
Using reactivity
server <- function(input, output) {
#Store reactive values
home.pts <- reactive({input$home.pts})
away.pts <- reactive({input$away.pts})
time <- reactive({input$time})
output$win_prob <- renderPrint({win_prob(home.pts(), away.pts(), time())})
}
Using ObserveEvent
server <- function(input, output) {
data <- reactiveValues()
observeEvent(input$goButton,{
data$home.pts <- input$home.pts
data$away.pts <- input$away.pts
data$time <- input$time
})
output$win_prob <- renderPrint({
req(data$home.pts) #to delay displaying result until user press Apply
win_prob(data$home.pts,data$away.pts, data$time)})
}
Now you can see the deference between the two approaches
Well you don't need to store all your inputs in reactive values. They already update themselves. When you have an actionButton, the best way to trigger an event from the click on the button is to use observeEvent. If I understood well, I would rewrite your server function like this:
# Define server to return win probability
server <- function(input, output) {
observeEvent(input$goButton, {
output$win_prob <- renderPrint({
win_prob(input$home.pts,
input$away.pts,
input$time)
})
})
}

How to render multiple output from the same analysis without executing it multiple time? (Shiny)

I am writing an shiny app in which contains an stochastic function generates four objects - one plot and three tables. However, I want to render each object in different tabs without being executing the function four times since this stochastic function will generates four different versions. I have been researched online and find a lot people recommend "reactive()" but I still don't quite understand how to apply it to my problem. How can I use those four objects on rendering with only one execution on the function?
My "server.R" structure basically looks like the below:
shinyServer(function(input, output) {
stochastic_function() {
...
plot1 <- ...
table1 <- ...
table2 <- ...
table3 <- ...
result <- list(plot, table1, table2, table3)
return(result)
}
output$plot <- renderPlot({
})
output$table1 <- renderTable({
})
output$table2 <- renderTable({
})
output$table3 <- renderTable({
})
...
So, I have tried something like below for the stochastic function:
model <- eventReactive(input$goButton, {
reactive(WG_Model(cdata = cdata(), # load data from outside env
sdata = sdata(), # load data from outside env
N = input$n,
end_date = input$end_date,
cpx_goal = input$cpx,
N_new = input$n2,
end_date_new = input$end_date2,
spend_range = input$s_range,
spend_incr = input$s_incr
)
)
})
The idea is to add an "GoButton" to initiate the function and then save all outputs in a reactive fun(). So I can render each output with:
output$plot <- renderPlot({
model$gplot
})
output$table <- renderTable({
model$table
})
# Render UI section
output$tb <- renderUI({
tabsetPanel(tabPanel("About Model", plotOutput("plot")),
tabPanel("About Model", tableOutput("table")))
})
However, I only got "Error: object of type 'closure' is not subsettable" in the UI output. Which part did I miss?
If your model() is a list and contains data for all tables and a plot, it should work as in my example.
In this app, after pressing a button, a random number and data for a table and a plot are generated. Then the number, data for table and a plot are returned as a list and rendered with appropriate render* functions.
This app illustrates that the model function won't be re-run after accessing it with model() in other reactive functions.
However, there is an odd thing...the plot is not always rendered. You sometimes have to click the button few times to get the plot. The table is working always.
library(shiny)
ui <- shinyUI(fluidPage(
br(),
actionButton("numb", "generate a random numbers"),
br(),
br(),
verbatimTextOutput("text"),
plotOutput("plot"),
tableOutput("table")
))
server <- shinyServer(function(input, output) {
model <- eventReactive(input$numb, {
# draw a random number and print it
random <- sample(1:100, 1)
print(paste0("The number is: ", random))
# generate data for a table and plot
data <- rnorm(10, mean = 100)
table <- matrix(data, ncol = 2)
# create a plot
Plot <- plot(1:length(data), data, pch = 16, xlab ="", ylab = "")
# return all object as a list
list(random = random, Plot = Plot, table = table)
})
output$text <- renderText({
# print the random number after accessing "model" with brackets.
# It doesn't re-run the function.
youget <- paste0("After using model()$random you get: ", model()$random,
". Compare it with a value in the console")
print(youget)
youget
})
output$plot <- renderPlot({
# render saved plot
model()$Plot
})
output$table <- renderTable({
model()$table
})
})
shinyApp(ui = ui, server = server)

Resources