Passing user input in Shiny to a URL query string - r

I have a question that I'm having trouble getting to work. I have a Shiny app that I want to accept two user input, send it back from ui.R to server.R, and insert that as a variable into a URL query string to download the file from a database. At first, we hardcoded the values to test the algorithm but we eventually want to make it user defined. I thought that saving as a variable and replacing it in the query string would work, but it didn't... I tried to concatenate pieces of the URL and I'm getting an error "Warning: Error in cat: argument 1 (type 'closure') cannot be handled by 'cat'". I tried to search online but couldn't find a good solution to my problem. Here is my code so far... As you see in the code, what I want to get is at least form the url and showing it as text on the ui just to see that it is being dynamic. Then when I know I can insert the user input, then I can continue on with storing the downloaded file.
#ui.R
library(shiny)
library(leaflet)
library(foreach)
library(ape)
library(data.table)
library(DT)
# Choices for the genetic distance model
geneticDistanceModel <- c(
"raw" = "raw",
"JC69" = "JC69",
"K80" = "K80",
"F81" = "F81",
"K81" = "K81",
"F84" = "F84",
"BH87" = "BH87",
"T92" = "T92",
"TN93" = "TN93",
"GG95" = "GG95",
"logdet" = "logdet",
"paralin" = "paralin"
)
shinyUI(navbarPage("TeMPuЯa", id="nav", position = c("fixed-top"),
# needed to keep fixed-top navbar from obscuring content
header = tags$style(type = "text/css", "body {padding-top: 70px;}"),
collapsible = "true",
tabPanel("Tool",
h1("Instructions"),
p("Placeholder"),
sidebarLayout(
sidebarPanel(
textInput("taxonomy", label = h4("Enter taxonomy group:"), value = "Porifera"),
textInput("geography", label = h4("Enter geographical location:"), value = "all"),
sliderInput("latitude", label = h4("Latitude difference"), min = 10, max = 30, value = 20),
sliderInput("genetic", label = h4("Genetic similarity threshold"), min = 10, max = 20, value = 15),
sliderInput("outgroups", label = h4("Select a distance from the outgroup"), min = 1, max = 2, value = 1.3, step = 0.1),
selectInput("distanceModels", label = h4("Select a genetic distance model"), geneticDistanceModel, selected = "K80"),
submitButton("Submit"),
br(),
downloadButton("download", label = "Download CSV")
),
mainPanel(
leafletOutput("worldmap"),
br(),
div(style='height:300px; width:850px; overflow:scroll',
DT::dataTableOutput("url", width = 850)),
textOutput("text")
)
)
),
tabPanel("Genetic Distance Models Info",
h1("Genetic distance models:"),
a("Link to more explanation for the distance models used in R", href = "http://svitsrv25.epfl.ch/R-doc/library/ape/html/dist.dna.html"),
br(),
p(strong("raw:") ,"This is simply the proportion or the number of sites that differ between each pair of sequences. This may be useful to draw 'saturation plots'."),
p(strong("JC69:") ,"This model was developed by Jukes and Cantor (1969)."),
p(strong("K80:") ,"The distance derived by Kimura (1980), sometimes referred to as 'Kimura's 2-parameters distance'."),
p(strong("F81:") ,"Felsenstein (1981) generalized the Jukes-Cantor model."),
p(strong("K81:") ,"This model is called the Kimura's 'three substitution types model' (3ST), and is sometimes referred to as 'Kimura's 3-parameters distance'."),
p(strong("F84:") ,"This model generalized K80, and was first introduced by Felsenstein in 1984."),
p(strong("BH87:") ,"Barry and Hartigan (1987)."),
p(strong("T92:") ,"Tamura (1992) generalized the Kimura model."),
p(strong("TN93:") ,"Tamura and Nei (1993) model."),
p(strong("GG95:") ,"Galtier and Gouy (1995) model."),
p(strong("logdet:") ,"The Log-Det distance, developed by Lockhart et al. (1994), is related to BH87. However, this distance is symmetric."),
p(strong("paralin:") ,"Lake (1994) developed the paralinear distance which can be viewed as another variant of the Barry-Hartigan distance.")
)
))
# server.R
library(shiny)
library(leaflet)
library(foreach)
library(ape)
library(data.table)
library(DT)
source("tsvtoDataFrame.R")
shinyServer(function(input, output, session) {
# Create the map
output$worldmap <- renderLeaflet({
leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
setView(lng = -93.85, lat = 37.45, zoom = 4)
})
textInput <- reactive({
var1 <- "http://www.boldsystems.org/index.php/API_Public/combined?taxon="
var2 <- "&geo="
var3 <- "&format=tsv"
paste(c(var1), c(input$taxonomy), c(var2), c(input$geography), c(var3))
})
output$text <- renderText({
textInput
})
output$url <- DT::renderDataTable(
dfMatchOverallBest,
options = list(scrollX = TRUE)
)
})

textInput is a reactive, so you should use
output$text <- renderText({
textInput()
})
Also you should probably use paste0 instead of paste to get your URL, and the c() command is not necessary.

Related

How to filter a column in shiny whose name is an output from a slider

I have a dashboard where slider is getting updated based on a dropdown widget. My issue is that dropdown selects the name of the column, and slider filters the selected column. The issue is when i create reactive filtered dataset: specifically this line: filter(input$selectx > input$my_slider[1]. i understand that it does not work cause the input$selectx is a character name of the column (eg "mean_radius", and I need a name without quotations (eg mean_radius). I tried quote(), {{}} and other functions but could not sort it out
#loading packages
library(shiny)
library(tidyverse)
library(datateachr) #cancer_sample dataset was used from this data package
library(rstatix)
library(shinythemes)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(title = "Cancer", titleWidth = 300),
dashboardSidebar(
width = 300,
selectInput("selectx", label = h3("Select X Variable"),
choices = list("radius_mean", "texture_mean", "perimeter_mean", "area_mean"),
selected = "area_mean"),
tags$br(),
sliderInput("my_slider",
label = h3("Range of X Variable"),
min = min(cancer_sample$area_mean, na.rm = TRUE),
max = max(cancer_sample$area_mean, na.rm = TRUE),
value = c(143.5,2501))
),
dashboardBody(
#makes the place holder for the plot
box(title = "Scatter Plot", solidHeader = TRUE, collapsible = TRUE, width = 12, plotOutput("my_plot", click = "plot_click")),
box(title = "Data Table", solidHeader = TRUE, collapsible = TRUE, width = 12, tableOutput("my_data"))
)
)
server <- function(input, output, session) {
#makes a reactive function to minimize repeated code
filtered <- reactive({
#the dataset that is being used
cancer_sample %>%
#filters the data set based on the area mean range from the slider, and the check boxes that are selected
filter(input$selectx > input$my_slider[1],
input$selectx < input$my_slider[2])
})
observe({
col <- cancer_sample %>% select(input$selectx)
#makes a slider that you can manipulate to show only data points that has an area mean that falls in the certain range
updateSliderInput(session, "my_slider",
value = col,
min = min(col, na.rm = TRUE),
max = max(col, na.rm = TRUE))
})
output$my_plot <- renderPlot({
filtered() %>%
#produces a graph with area_mean on the x-axis and perimeter_mean on the y-axis.
ggplot(aes_string(x = input$selectx, y = perimeter_mean)) +
geom_point(aes(colour = diagnosis))
})
output$my_data <- renderTable(
filtered() %>%
select(ID:area_mean)
)
}
# Run the application
shinyApp(ui = ui, server = server)
Your problem is not shiny connected, so the question could be easily simplified.
Unfortunately you do not provide the dataset here. So I could not provide a working example.
quote will always return what is inside quote(input$selectx) -> input$selectx so this for sure not a solution.
Please use the e.g. .data solution here.
airquality %>% filter(.data[[input$selectx]] > input$my_slider[1],
.data[[input$selectx]] < input$my_slider[2])

Using UpdateTabsetPanel with Dynamic UI

I'm trying to create an app which allows the user to dynamically transform variables in a linear regression model to understand the impact that doing so has on regression diagnostics (residual plots etc.).
In the app below, you will see that the user has the option to log transform the target variable, and upon doing so, is presented with three types of log transformations to perform. This works fine with a single variable, but I'm trying to provide the ability to do so with the predictors as well. This gets particularly complicated because the number of predictors is not fixed and is based on a user's selection.
I recognize that one issue here is that I need to create a separate tabsetPanel for each predictor. For this reason, I created a function to create the tabsetPanel, which allows the user to specify the ID. This component of the app works fine, but when it comes time to try and render the dynamic parameter selections, to app doesn't function. Does anyone have any idea how to fix this? Apologies if the reproducible example below is a bit long - couldn't figure out a way to simplify without losing the scope of the general question.
## libraries
library(tidyverse)
library(shiny)
## stored data objects, including variable and transformation names
dat <- mtcars
var_names <- dat %>% select(1:3) %>% colnames %>% sort
tran_names <- c("None", "Logarithmic")
## create conditional UI for transformation parameters
param_select <- function(object_name) {
tabsetPanel(
id = object_name,
type = "hidden",
tabPanel("None",
fluidRow()),
tabPanel("Logarithmic",
fluidRow(column(width = 3,
selectInput(inputId = "log_param",
label = "Type:",
choices = c("Natural", "Base 2", "Base 10"))))))
}
## create base UI
ui <- fluidPage(
fluidRow(column(width = 2,
## input selector for target variable
selectInput(inputId = "target",
label = "Target Variable",
choices = var_names)),
column(width = 2,
## input selector for target variable transformation, excluding polynomials
selectInput(inputId = "target_trans",
label = "Select Transformation",
choices = tran_names %>% .[.!="Polynomial"])),
column(width = 8, param_select("params"))),
## input selector for number of predictors
numericInput(inputId = "preds_n",
label = "Select Number of Predictors",
value = 1,
min = 1,
max = length(var_names) - 1,
width = "190px"),
## stored layout for dynamic UI
fluidRow(column(width = 2, uiOutput("preds_ui")),
column(width = 2, uiOutput("pred_trans_ui")),
column(width = 8, uiOutput("pred_param_ui")))
)
server <- function(input, output, session) {
## parameter selections for target variable
observeEvent(input$target_trans, {
updateTabsetPanel(session = session, inputId = "params", selected = input$target_trans)
})
## create objects to store individual predictors
preds <- reactive(paste0("Predictor ", seq_len(input$preds_n)))
output$preds_ui <- renderUI({
preds() %>% map(~ selectInput(inputId = .x,
label = .x,
choices = var_names,
selected = isolate(input[[.x]])) %||% "")
})
## create objects to store individual predictors transformations
pred_trans <- reactive(paste0("Transformation ", seq_len(input$preds_n)))
output$pred_trans_ui <- renderUI({
pred_trans() %>% map(~ selectInput(inputId = .x,
label = .x,
choices = tran_names,
selected = isolate(input[[.x]])) %||% "")
})
## create objects to store individual predictors transformations parameters
## this is where i'm stuck :(
pred_params <- reactive(paste0("Parameter ", seq_len(input$preds_n)))
pred_param_select <- reactive(pred_params() %>%
map(~param_select(object_name = .x) %>%
setNames(nm = .x)))
output$pred_param_ui <- renderUI({
pred_params() %>%
map(~observeEvent(input[[.x]], {
updateTabsetPanel(session = session, inputId = "params", selected = input[[.x]])
}))
})
}
shinyApp(ui, server)
Note that this question is an extension of my previous question here.

Preventing Shiny selectInput from evaluating prematurely when updating a reactive plot

I am working on a Shiny app that generates various plots and allows users to change graphing parameters. For this, I'm using a combination of selectInput, numericInput, and checkboxInput functions after the plot is generated (conditionalPanel). I packaged the code so that the data.frame used for the graph is calculated reactively (to allow flexible subsetting before plotting). Everything works great, but when I want to update some graphing parameters (such as colors to use via selectInput), the code breaks down because it evaluates prematurely before I select all the necessary colors (i.e. when there are 4 colors needed, code breaks right after selecting the first color).
I know about debounce function to delay evaluation, but I don't want to use it because:
I like the instant changes in the graph when I update other parameters
Selection of colors can take some time, so it is difficult to set a predetermined delay time/time interval
One solution can be to add an actionButton shown conditionally (along with other graphing parameters) to regulate the firing of the reactive input values (see below). This is not ideal because after changing parameters, I need to click on update to renew the graph. Also, I'm not sure how this would even work because the km_graph is already a reactive plot object. Alternatively, is there a solution for regulating selectInput specifically so that until all the colors selected, it is not evaluated?
I read several posts on this issue but I couldn't find a solution that works with the design of my code. I will try to write sections of my ui and server to give an idea of what I'm trying to do:
ui.R
# ...
mainPanel(
plotOutput("km_graph"),
# Conditional panel prompted only after the km_graph is generated
conditionalPanel(
condition = "output.km_graph" ,
checkboxInput("km_risk", label="Show risk table", F),
selectInput("km_medline", label = "Mark median survival",
selected = "hv",
choices = c("None" = "none",
"Horizontal-Vertical" = "hv",
"Vertical" = "v",
"Horizontal" = "h")),
sliderInput("km_xlim", label="days", value = 6000, min = 10, max=10000),
selectInput("km_pal", "Select colors", multiple = T,
selectize = T,
selected = "jco",
choices = list(`Pre-made palettes` = list("npg","aaas", "lancet", "jco",
"ucscgb", "UChicago",
"simpsons", "rickandmorty")
`Individual colors` = as.list(color_choices))
)
# Need to find a way to prevent evaluating before all the colors are selected for km_pal
# Maybe another actionButton() here to update graph after all the parameters are selected?
server.R
#...
# km_results() is the reactive object containing survival analysis results
# km_dat() is the reactive data frame used in the analyses
output$km_graph <- renderPlot({
survminer::ggsurvplot(km_results(), data = km_dat(),
pval = input$km_pval,
pval.method = input$km_pval,
risk.table = input$km_risk,
conf.int = input$km_confint,
surv.median.line = input$km_medline,
break.time.by = input$km_breaktime,
legend="right",
xlim=c(0, input$km_xlim),
palette = input$km_pal) ###### This breaks due to premature evaluation
})
Full Reprex
shinyApp(
ui = basicPage(
selectInput("dat", "Select data",
selected = "iris", choices = c("iris")),
actionButton("go", "Go!"),
plotOutput("plot"),
conditionalPanel(
h3("graphing options"),
condition = "output.plot",
checkboxInput("plot_point", "Show points", T),
selectizeInput("plot_colors", "Select colors", selected="jco",
choices = list(`premade`=list("jco", "npg"),
`manual`=list("red", "black", "blue")))
)
),
server = function(input, output) {
dat <- reactive({
if(input$dat == "iris") iris
})
output$plot <- renderPlot({
req(input$go)
ggpubr::ggscatter(dat(), "Sepal.Length", "Sepal.Width",
color="Species", palette=input$plot_colors)
})
}
)
Thanks for the insights!
I'm not 100% sure I fully understood, but you could for example pass the plot_colors input in a reactive variable that is triggered by an action button "Apply colors" ?
(you need to add multiple = TRUE in the selectizeInput's arguments)
Here is an example of code based on your reprex:
shinyApp(
ui = basicPage(
selectInput("dat", "Select data",
selected = "iris", choices = c("iris")),
actionButton("go", "Go!"),
plotOutput("plot"),
conditionalPanel(
h3("graphing options"),
condition = "output.plot",
checkboxInput("plot_point", "Show points", T),
selectizeInput("plot_colors",
"Select colors",
selected="jco",
multiple = TRUE,
choices = list(`premade`=list("jco", "npg"),
`manual`=list("red", "black", "blue"))),
actionButton(inputId = "apply", label = "Apply colors")
)
),
server = function(input, output) {
dat <- reactive({
if(input$dat == "iris") iris
})
params_curve <- shiny::eventReactive(eventExpr = input$apply,
{
return(list(colors = input$plot_colors))
},
ignoreNULL = F,
ignoreInit = F
)
output$plot <- renderPlot({
req(input$go)
ggpubr::ggscatter(dat(), "Sepal.Length", "Sepal.Width",
color="Species", palette=params_curve()$colors)
})
}
)
If you select "red", "black", and "blue", then the dimension of your plot_colors variable is 3. So, the plot is rendered.

Unable to render Gauge from Flexdashboard library in Shiny app

I am trying to create a Shiny app which
a) prompts user to upload a file which contains numeric data,
b) reads the file and assigns the data points to different variables,
c) calculates new variables from the captured variables
d) display a 'Gauge' using the calculated variables
The code successfully executes but the Gauge chart is not rendered properly. There is no error or warning message either. Instead, I am getting the following message:
"Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON."
And instead of the gauge output I am getting that tiny spec in the middle, as seen in the attached image.
The entire code is fairly long, hence providing just the relevant snippets of code.
Would really appreciate if you can help fix this.
library(shiny)
library(flexdashboard)
ui <- fluidPage(
tabPanel("Sensitivity Analysis",
sidebarLayout(
sidebarPanel(
uiOutput("Sensitivity_Analysis")
),
mainPanel(
gaugeOutput("sensitivity", width = "600px", height = "600px")
)
)
),
server <- function (input, output)
{
output$input_financials=renderUI({
fluidRow(fileInput("file1", "Choose CSV File",multiple = FALSE,accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
actionButton("process","Process"))})
data_input=reactiveValues()
observeEvent(input$process,{
file_input <- input$file1
if (is.null(file_input)) {
return(NULL)}
## File is read and all the inputs are assigned to variables
....
## Output for Gauge begins
output$sensitivity <- flexdashboard::renderGauge({
gauge_limit <- data_input$wc_value
data_input$cash_rel_dpo <- ## Formula for cash_del_dpo
data_input$cash_rel_dro <- ## Formula for cash_del_dro
data_input$cash_rel_dio <- ## Formula for cash_del_dio
data_input$wc_predicted_value <- (data_input$wc_predicted_value - data_input$cash_rel_dpo - data_input$cash_rel_dro - data_input$cash_rel_dio)
gauge(data_input$wc_predicted_value, min = 0, max = gauge_limit,
gaugeSectors(success = c(0, 10000),
warning = c(10001, 50000),
danger = c(50001, 1000000000))
)
})
shinyApp(ui = ui, server = server)
Screenshot of the output generated upon executing the code
There's a similar gauge in package billboarder, try this example:
library(shiny)
library(billboarder)
ui <- fluidPage(
tabPanel(
title = "Sensitivity Analysis",
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv","text/comma-separated-values,text/plain",".csv")),
actionButton(inputId = "process", label = "Process (click here to refresh the gauge)")
),
mainPanel(
billboarderOutput("sensitivity", width = "400px", height = "400px")
)
)
)
)
server <- function (input, output) {
data_input <- reactiveValues(x = 0)
observeEvent(input$process, {
data_input$x <- sample.int(1e5, size = 1)
}, ignoreInit = TRUE)
## Output for Gauge begins
output$sensitivity <- renderBillboarder({
billboarder() %>%
bb_gaugechart(
value = data_input$x,
name = "Predicted value",
steps = c(1e4, 5e4, 1e5),
steps_color = rev(c("#FF0000","#F6C600", "#60B044"))
) %>%
bb_gauge(
min = 0, max = 1e5,
units = "",
label = list(
format = htmlwidgets::JS("function(value, ratio) {return d3.format(',')(value);}") # format value with thousand separator
),
width = 80
)
})
}
shinyApp(ui = ui, server = server)

How to Store Monte Carlo Simulation Outputs Within a reactive() Function In Shiny

I have been working on a side project that involves a simple shiny app that allows users to input the parameters of a dice roll for a board game then have the code preform 10,000 rolls with those parameters and present the average of the rolls. I have a basic code that successfully makes this happen but I am struggling how to make it into a shiny app to make accessible to others.
The issue I face is that in the server part of the shiny code I do not know how to store the intermediate results within a single reactive() function. Is there a local storage option that works with a repeating function?
The code I am using is:
# Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("10,000 Roll Simulator"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
numericInput(inputId = "num_tac", label = "TAC",
value =1 , min = 1, max = 20),
numericInput(inputId = "num_def", label = "DEF",
value =1 , min = 1, max = 10),
numericInput(inputId = "num_arm", label = "ARM",
value =0 , min = 0, max = 10)
)
)
)
server <- function(input, output){
data()<- reactive({
One_roll<- function(){dice <- sample(1:6, size = input$num_tac, replace = TRUE)
return(sum((dice >= input$num_def)-input$num_arm))
sims<-replicate(10000, One_roll()}
output$stats <- renderPrint({mean(data())})
}
# Run the application
shinyApp(ui = ui, server = server)
Any help would be greatly appreciated, thank you!
A few issues with your code :
data()<- is not allowed. Use data<- instead then call it with data()
Using input$ inside a function is definitely not the right way to pass parameters
This is a modified server function where the One_roll function is defined outside the reactive, but called inside, with input passed as parameters:
server <- function(input, output){
One_roll<- function(num_tac,num_def,num_arm){
dice <- sample(1:6, size = num_tac, replace = TRUE)
sum((dice >= num_def)-num_arm)
}
data<- reactive(replicate(10000, One_roll(input$num_tac,input$num_def, input$num_arm )))
output$stats <- renderPrint(mean(data()))
}
And also you need a textOutput in the ui function to call the renderText for example:
ui <- fluidPage(
# Application title
titlePanel("10,000 Roll Simulator"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
numericInput(inputId = "num_tac", label = "TAC",
value =1 , min = 1, max = 20),
numericInput(inputId = "num_def", label = "DEF",
value =1 , min = 1, max = 10),
numericInput(inputId = "num_arm", label = "ARM",
value =0 , min = 0, max = 10)
), mainPanel = textOutput("stats")
)
)
You could also save all the user entered data into a static variable first and then use them as normal variables.
server <- function(input, output) {
temp <- reactive({
tac <- input$num_tac
def <- input$num_def
arm <- input$num_arm
One_roll <- function(tac, def, arm) {
dice <- sample(1:6, size = tac, replace = TRUE)
sum((dice >= def) - arm)
}
data <- replicate(10000, One_roll(tac, def, arm))
#remember to print the data again so the results will be saved to temp
data
})
output$stats <- renderPrint({
mean(temp())
})
}

Resources