I want to print a text first, before processing the code and then print a confirmation after the code is executed.
Here is my code (ui and server of app.R):
All unspecified variables are initiated within the app.R file.
ui <- fluidPage(
# Application title
titlePanel(h1("Order2Ship", align="center")),
# Sidebar iputs
sidebarLayout(
sidebarPanel( #LONG LIST OF INPUTS
),
# On Screen output
mainPanel(
textOutput("START"),
textOutput("Confirm")
)
)
)
# Underlining code for output (computes the whole each time an input is changed)
server <- function(input, output) {
observeEvent(input$Do, { # ignores all return values
output$START <- renderText({"Starting Analysis"})
O2S( #LONG LIST OF PARAMETERS, FROM INPUTS
)
output$Confirm <- renderText({"Analysis Done"})
})
}
# Run the application
shinyApp(ui = ui, server = server)
I do not need any returns from the function O2S, it basically takes one file as input and generates a solution file. But, both the text outputs are showing at the same time, after the function has run. I cannot figure it out. I just started out with Shiny, so sorry for such a naïve question.
Hi you can use shinyjs to create a chainevent something like this
library(shinyjs)
library(shiny)
ui <- fluidPage(
# Application title
titlePanel(h1("Order2Ship", align="center")),
# Sidebar iputs
sidebarLayout(
sidebarPanel( #LONG LIST OF INPUTS
actionButton(inputId = "Do",
label = "Start")
),
# On Screen output
mainPanel(
textOutput("START"),
textOutput("Confirm"),
useShinyjs()
)
)
)
# Underlining code for output (computes the whole each time an input is changed)
server <- function(input, output) {
startText <- eventReactive({input$Do},{
runjs("Shiny.onInputChange('analysisStarted',Date.now())")
"Starting Analysis"
},
ignoreInit = TRUE)
output$START <- renderText({startText()})
observeEvent(input$analysisStarted, { # ignores all return values
temp <- NULL
for(i in seq(50000)){
temp <- c(temp,i)
}
runjs("Shiny.onInputChange('analysisFinished',true)")
},
ignoreInit = FALSE)
confirmText <- eventReactive({input$analysisFinished},{
"Analysis Done"
},
ignoreInit = FALSE)
output$Confirm <- renderText({confirmText()})
}
# Run the application
shinyApp(ui = ui, server = server)
hope this helps!
Related
I would like to have an action button in R Shiny that samples three elements of a character variable and returns each on its own line. I have seen that htmltools can be used to break the text of the action button itself onto new lines, but I don't see an obvious way to pass such commands into the output of the button, especially when using the sample() function.
In the toy shiny app below, the actionButton prints three greek letters on one line,
alpha beta delta
I would like each sampled element to appear on its own line,
alpha
beta
delta
Below is the toy app
library(shiny)
# Define UI ----
ui <- fluidPage(
titlePanel("Toy"),
# Copy the line below to make an action button
actionButton("greek", label = "Greek letters"),
verbatimTextOutput("text")
)
# Define server logic ----
server <- function(input, output, session) {
observeEvent(input$greek, {
greek <- c("alpha","beta","gamma","delta")
})
observeEvent(input$greek,{
output$text <- renderText(sample(greek,3))
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Here, try this:
library(shiny)
library(glue)
# Define UI ----
ui <- fluidPage(
titlePanel("Toy"),
# Copy the line below to make an action button
actionButton("greek", label = "Greek letters"),
verbatimTextOutput("text")
)
# Define server logic ----
server <- function(input, output, session) {
greeks <- eventReactive(input$greek, {
sample(c("alpha", "beta", "gamma", "delta"), size = 3)
})
output$text <- renderText(
sample(greeks(), 3) |> glue_collapse(sep = "\n")
)
}
# Run the app ----
shinyApp(ui = ui, server = server)
i have a question regarding Shiny and the usage of Data frames.
I think i understood that i need to create isolated or reactive environmentes to interact with, but if i try to work with the Dataframe i get an error message:
Error in pfData: konnte Funktion "pfData" nicht finden
i tried to manipulate the dataframe by this code:
server <- function(input, output) {
observeEvent(input$go,
{
pf_name <- reactive({input$pfID})
pf_date <- reactive({input$pfDate})
if (pf_name()!="please select a PF") {
pfData <- reactive(read.csv(file =paste(pf_name(),".csv",sep=""),sep=";",dec=","))
MDur <- pfData()[1,15]
pfData <- pfData()[3:nrow(pfData()),]
Total = sum(pfData()$Eco.Exp...Value.long)
}
})
}
If i manipulate my Dataframe in the console it works just fine:
pfData <- pfData[3:nrow(pfData),]
Total = sum(pfData$Eco.Exp...Value.long)
Assets = sum(as.numeric(gsub(",",".",gsub(".","",pfData$Value,fixed=TRUE),fixed=TRUE)))
pfData$Exposure <- with(pfData, Eco.Exp...Value.long /Total)
can you help me?
Edit:
library(shiny)
ui <- fluidPage(
fluidRow(
column(6, offset =3,
wellPanel(
"Choose Mandate and Date",
fluidRow(
column(4,selectInput("pfID",label = "",
choices = list("please select a PF","GF25",
"FPM"),
selected = "please select a PF") ),
column(4, dateInput("pfDate",label="",value = Sys.Date()) ),
column(2, actionButton("go","Submit")),column(2,textOutput("selected_var"))
)
)
)
)
)
# Define server logic ----
server <- function(input, output) {
pfDataReactive <- reactive({
input$go
if (pf_name()!="please select a PF") {
pfData <- read.csv(file =paste(pf_name(),".csv",sep=""),sep=";",dec=",")
MDur <- pfData[1,15]
pfData <- pfData[3:nrow(pfData),]
Total = sum(pfData$Eco.Exp...Value.long)
Assets = sum(as.numeric(gsub(",",".",gsub(".","",pfData$Value,fixed=TRUE),fixed=TRUE)))
pfData$Exposure <- with(pfData, Eco.Exp...Value.long /Total)
pfData
output$selected_var <- renderText({paste(MDur)})
}
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Thank you
Stefan
Without a working example, it's imposible to be sure what you're trying to do, but it sounds like you need a reactive rather than using observeEvent.
Try something like
pfDataReactive <- reactive({
input$go
pfData <- read.csv(file =paste(pf_name(),".csv",sep=""),sep=";",dec=",")
Total = sum(pfData$Eco.Exp...Value.long)
Assets = sum(as.numeric(gsub(",",".",gsub(".","",pfData$Value,fixed=TRUE),fixed=TRUE)))
pfData$Exposure <- with(pfData, Eco.Exp...Value.long /Total)
pfData
})
And then use pfDataReactive() in your Shiny app's server function wherever you would refer to pfData in your console code.
The standalone reference to input$go ensures the reactive will update whenever input$go changes/is clicked/etc.
Update
There are still significant issues with your code. You've added an assignment to an output object as the last line of the reactive I gave you, so the reactive always returns NULL. That's not helpful and is one of the reasons why it "doesn't active at all"...
Second, you test for the existence of an reactive/function called pf_name when the relevant input object appears to be input$pfID. That's another reason why the reactive is never updated.
Note the change to the definition of input$pfID that I've made to improve the readability of the pfDataReactive object. (This change also probably means that you can do away with input$go entirely.)
As you say, I don't have access to your csv file, so I can't test your code completely. I've modified the body of the pfDataReactive to simply return the mtcars dataset as a string. I've also edited the code I've commented out to hopefully run correctly when you use it with the real csv file.
This code appears to give the behaviour you want,. Though, if I may make a subjective comment, I think the layout of your GUI is appaling. ;=)
library(shiny)
ui <- fluidPage(
fluidRow(
column(6, offset =3,
wellPanel(
"Choose Mandate and Date",
fluidRow(
column(4,selectInput("pfID",label = "",
# Modified to that "Pleaseselect a PF" returns NULL
choices = list("please select a PF"="","GF25", "FPM"),
selected = "please select a PF") ),
column(4, dateInput("pfDate",label="",value = Sys.Date()) ),
column(2, actionButton("go","Submit")),column(2,textOutput("selected_var"))
)
)
)
)
)
# Define server logic ----
server <- function(input, output) {
pfDataReactive <- reactive({
# Don't do anything until we have a PF csv file
req(input$pfID)
input$go
# Note the change to the creation of the file name
# pfData <- read.csv(file =paste(input$pfID,".csv",sep=""),sep=";",dec=",")
# pfData <- pfData[3:nrow(pfData),]
# Total = sum(pfData$Eco.Exp...Value.long)
# Assets = sum(as.numeric(gsub(",",".",gsub(".","",pfData$Value,fixed=TRUE),fixed=TRUE)))
# pfData$Exposure <- with(pfData, Eco.Exp...Value.long /Total)
# MDur <- pfData[1,15]
# If you want to print MDur in the selected_var output, MDur should be the retrun value from this reactive
# MDur
mtcars
})
output$selected_var <- renderText({
print("Yep!")
as.character(pfDataReactive())
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Next time, please, please, make more effort to provide a MWE. This post may help.
This is a good introduction to Shiny.
I am trying to capture the url that has been selected when a person presses the "GET URLS" button on the app.
What should happen is that the event reactive() should look at the input$go_button and see that it has been pressed - it should then perform the expression to take the chosen url from the select input- unfortunately it does nothing.
I have tried debugging with browser() but still had no affect.
All i am trying to do is capture the url that has been selected when a person "presses" the "GET URLS" button.
my sample code is below:
library(shiny)
# Use a fluid Bootstrap layout
ui <- fluidPage(
# Give the page a title
titlePanel("testing select"),
# Generate a row with a sidebar
sidebarLayout(
# Define the sidebar with one input
sidebarPanel(
selectInput("url_selection", "select url:",
choices = c(
'/multi-task/',
"/personal-account",
"/paperless"
)
),
actionButton(inputId = "go_button", label = "Get URLS")
),
# Create a spot for the barplot
mainPanel(
textOutput(outputId = "urls_selected_print")
)
)
)
server <- function(input, output) {
url_capture <- reactive({eventReactive(eventExpr = input$go_button,
valueExpr = {
message("capturing url chosen in selectize input")
chosen_url <- input$url_selection
browser()
return(chosen_url)
})
})
}
shinyApp(ui, server)
You can use observeEvent to capture event when go_button has been pressed. You can store the selection in a reactiveVal which can be displayed in your output.
server <- function(input, output) {
rv <- reactiveVal(NULL)
observeEvent(input$go_button, {
message("capturing url chosen in selectize input")
rv(input$url_selection)
})
output$urls_selected_print <- renderText({rv()})
}
Small alternative to Ben's answer (you just have to remove reactive, because eventReactive is already reactive):
server <- function(input, output) {
url_capture <- eventReactive(eventExpr = input$go_button,
valueExpr = {
message("capturing url chosen in selectize input")
chosen_url <- input$url_selection
return(chosen_url)
})
output$urls_selected_print <- renderPrint({
url_capture()
})
}
I understand that reactive values notifies any reactive functions that depend on that value as per the description here
based on this I wanted to make use of this property and create a for loop that assigns different values to my reactive values object, and in turn I am expecting another reactive function to re-execute itself as the reactive values are changing inside the for loop. Below is a simplified example of what i am trying to do:
This is the ui.R
library(shiny)
# Define UI
shinyUI(pageWithSidebar(
titlePanel("" ,"For loop with reactive values"),
# Application title
headerPanel(h5(textOutput("Dummy Example"))),
sidebarLayout(
#Sidebar
sidebarPanel(
textInput("URLtext", "Enter csv of urls", value = "", width = NULL, placeholder = "Input csv here"),
br()
),
# Main Panel
mainPanel(
h3(textOutput("caption"))
)
)
))
This is the server file:
library(shiny)
shinyServer(function(input, output) {
values = reactiveValues(a = character())
reactive({
url_df = read.table(input$URLtext)
for (i in 1:5){
values$a = as.character(url_df[i,1])
Sys.sleep(1)
}
})
output$caption <- renderText(values$a)
})
This does not give the expected result. Actually when I checked the content of values$a
it was null. Please help!
Rather than using a for loop, try using invalidateLater() with a step counter. Here's a working example that runs for me with an example csv found with a quick google search (first column is row index 1-100).
library(shiny)
# OP's ui code
ui <- pageWithSidebar(
titlePanel("" ,"For loop with reactive values"),
headerPanel(h5(textOutput("Dummy Example"))),
sidebarLayout(
sidebarPanel(
textInput("URLtext", "Enter csv of urls", value = "", width = NULL, placeholder = "Input csv here"),
br()
),
mainPanel(
h3(textOutput("caption"))
)
)
)
server <- function(input, output, session) {
# Index to count to count through rows
values = reactiveValues(idx = 0)
# Create a reactive data_frame to read in data from URL
url_df <- reactive({
url_df <- read.csv(input$URLtext)
})
# Reset counter (and url_df above) if the URL changes
observeEvent(input$URLtext, {values$idx = 0})
# Render output
output$caption <- renderText({
# If we have an input$URLtext
if (nchar(req(input$URLtext)) > 5) {
# Issue invalidation command and step values$idx
if (isolate(values$idx < nrow(url_df()))) {
invalidateLater(0, session)
isolate(values$idx <- values$idx + 1)
}
}
# Sleep 0.5-s, so OP can see what this is doing
Sys.sleep(0.5)
# Return row values$idx of column 1 of url_df
as.character(url_df()[values$idx, 1])
})
}
shinyApp(ui = ui, server = server)
Quick question on conditionalPanel for shiny/R.
Using a slightly modified code example from RStudio, consider the following simple shiny app:
n <- 200
# Define the UI
ui <- bootstrapPage(
numericInput('n', 'Number of obs', n),
conditionalPanel(condition = "input.n > 20",
plotOutput('plot') ),
HTML("Bottom")
)
# Define the server code
server <- function(input, output) {
output$plot <- renderPlot({
if (input$n > 50) hist(runif(input$n)) else return(NULL)
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
My objective is to hide the graph and move up the HTML text to avoid a gap. Now, you can see that if the entered value is below 20, the graph is hidden and the text "Bottom" is moved up accordingly. However, if the entered value is larger than 20, but smaller than 50, the chart function returns NULL, and while no chart is shown, the text "Bottom" is not moving up.
Question is: is there a way I can set a conditionalPanel such that it appears/is hidden based on whether or not a plot function returns NULL? The reason I'm asking is because the trigger a bit complex (among other things it depends on the selection of input files, and thus needs to change if a different file is loaded), and I'd like to avoid having to code it on the ui.R file.
Any suggestions welcome,
Philipp
Hi you can create a condition for conditionalPanel in the server like this :
n <- 200
library("shiny")
# Define the UI
ui <- bootstrapPage(
numericInput('n', 'Number of obs', n),
conditionalPanel(condition = "output.cond == true", # here use the condition defined in the server
plotOutput('plot') ),
HTML("Bottom")
)
# Define the server code
server <- function(input, output, session) {
output$plot <- renderPlot({
if (input$n > 50) hist(runif(input$n)) else return(NULL)
})
# create a condition you use in the ui
output$cond <- reactive({
input$n > 50
})
outputOptions(output, "cond", suspendWhenHidden = FALSE)
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
Don't forget to add the session in your server function and the outputOptions call somewhere in that function.