argument "sidebar" is missing, with no default when creating shiny script - shiny

I'm creating a shiny app for an app that predicts morphine consumption based on several variables. When I attempt to run the app I receive a sidebar error message stating I am missing script to create the sidebar ("argument "sidebar" is missing, with no default"). Here is my ui and server script.
#Load libraries
library(shiny)
library(shinydashboard)
library(ggplot2)
library(dplyr)
library(randomForest)
library(Metrics)
#R Shiny ui
ui <- dashboardPage(dashboardHeader(title = 'Morphine Consumption Explorer', titleWidth = 290))
#Sidebar layout
dashboardSidebar(sidebarMenu(id = "menu", sidebarMenuOutput("menu")))
sidebarMenu(menuItem("Plots", tabName = "plots", icon = icon('poll')),
menuItem("Dashboard", tabName = "dash", icon = icon('tachometer-alt')),
menuItem("Prediction", tabName = "pred", icon = icon('search')))
#pick variables
#Tabs layout
dashboardBody(tags$head(tags$style(HTML('.main-header .logo {font-weight: bold;}'))))
tabItems()
#Plots tab content
tabItem('plots',
#Histogram filter
box(status = 'primary', title = 'Filter for the histogram plot',
selectInput('num', "Numerical variables:", c("Age", "BMI", "IV_Fluids", "Operative_times", "Blood_loss", "Time_to_Aldrete_9", "morphine_consumption_24h1",
"VAS_basalR", "VAS_basalM", "VAS_2hrR", "VAS_2hrM", "VAS_4hrM", "VAS-4hrR",
"VAS_8hrR", "VAS_8hrM", "VAS_12hrR", "VAS_12hrM", "VAS_16hrR", "VAS_16hrM",
"VAS_24hrR", "VAS_24hrM", "QOR_psychological_support", "QOR_emotional_state",
"QOR_Physical_comfort", "QOR_physical_independence", "QOR_Pain", "Total")),
footer = 'Histogram plot for numerical variables'),
#Frequency plot filter
box(status = 'primary', title = 'Filter for the frequency plot',
selectInput('cat', 'Categorical variables:', c("ASA", "Postoperative_vomiting", "Sedation_0to8h", "Sedation_9to16h", "Sedation_17to24h")),
footer = 'Frequency plot for categorical variables'),
#Boxes to display the plots
box(plotOutput('histPlot')),
box(plotOutput('freqPlot')))
#Prediction tab content
tabItem('pred',
#Filters for categorical variables
box(title = 'Categorical variables',
status = 'primary', width = 12,
splitLayout(
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
cellWidths = c('0%', '19%', '4%', '19%', '4%', '19%', '4%', '19%', '4%', '8%'),
selectInput( 'p_group', 'group', c("0", "30", "60", "90")),
div(),
selectInput('p_ASA', 'ASA', c('1', '2', '3')),
div(),
selectInput( 'p_Sedation_17to24h', 'Ramsey Sedation at 17-24h', c('1', '2', '3', '4')),
div(),
radioButtons( 'p_Postoperative_vomiting', 'PONV', c('Yes', 'No')))),
#Filters for numeric variables
box(title = 'Numerical variables',
status = 'primary', width = 12,
splitLayout(cellWidths = c('22%', '4%','21%', '4%', '21%', '4%', '21%'),
sliderInput( 'p_Age', 'Age (year)', min = 0, max = 100, value = 0),
div(),
numericInput( 'p_BMI', 'BMI', 0),
div(),
numericInput( 'p_VAS_24hrM', 'VAS with Movement at 24hr', 0),
div(),
numericInput( 'p_QOR_psychological_support', 'QOR - Psychological Support', 0),
div(),
numericInput( 'p_QOR_Pain', 'QOR - Pain', 0),
numericInput( 'p_QOR_Physical_comfort', 'QOR - Physical Comfort', 0),
div(),
)),
#Box to display the prediction results
box(title = 'Prediction result',
status = 'success',
solidHeader = TRUE,
width = 4, height = 260,
div(h5('Morphine Consumption (mg):')),
verbatimTextOutput("value", placeholder = TRUE),
div(h5('Range of Morphine Consumption:')),
verbatimTextOutput("range", placeholder = TRUE),
actionButton('cal','Calculate', icon = icon('calculator'))),
#Box to display information about the model
box(title = 'Model explanation',
status = 'success',
width = 8, height = 260,
helpText('The following model will predict the total amount of morphine consumed by age, BMI, Visual Analog Scale at 24 hours with movement, and Quality of Recovery.'),
helpText('The name of the dataset used to train the model is "Short-term efficacy of preoperative Duloxetine for patients subjected to modified radical mastectomy A dose ranging randomized controlled trial", taken from the UCI Machine Learning Repository website. The data contains 17,379 observations and 16 attributes related to time and weather conditions.'),
helpText(sprintf('The prediction is based on a random forest supervised machine learning model. Furthermore, the models deliver a mean absolute error (MAE) of %s morphine consumed, and a root mean squared error (RMSE) of %s total number of morphine consumed.', round(mae_rf, digits = 0), round(rmse_rf, digits = 0)))))
# R Shiny server
server <- shinyServer(function(input, output) {
#Univariate analysis
output$histPlot <- renderPlot({...})
output$freqPlot <- renderPlot({...})
#Dashboard analysis
output$linePlot <- renderPlot({...})
output$barPlot <- renderPlot({...})
#Prediction model
#React value when using the action button
a <- reactiveValues(result = NULL)
observeEvent(input$cal, {
#Copy of the test data without the dependent variable
test_pred <- test_set[-10]
#Dataframe for the single prediction
values = data.frame(mnth = input$p_mnth,
Group = input$p_group,
ASA = input$p_ASA,
Sedation_17to24hr = input$p_Sedation_17to24h,
PONV = input$p_Postoperative_vomiting)
#Include the values into the new data
test_pred <- rbind(test_pred,values)
#Single preiction using the randomforest model
a$result <- round(predict(model_rf,
newdata = test_pred[nrow(test_pred),]),
digits = 0)
})
output$value <- renderText({
#Display the prediction value
paste(a$result)
})
output$range <- renderText({
#Display the range of prediction value using the MAE value
input$cal
isolate(sprintf('(%s) - (%s)',
round(a$result - mae_rf, digits = 0),
round(a$result + mae_rf, digits = 0)))
})
})
shinyApp(ui, server)
I appreciate any feedback.
Thank you. A
I tried manipulating the sidebar script after I ran the app. I'm expecting a shiny app that allows me to picture variables and estimate morphine consumption.

The header, sidebar and body functions need to passed as parameters to the dashboardPage(header, sidebar, body, title = NULL) function. Please check the following:
# Load libraries
library(shiny)
library(shinydashboard)
library(shinydashboardPlus)
library(ggplot2)
library(dplyr)
library(randomForest)
library(Metrics)
# R Shiny ui
ui <- dashboardPage(header = dashboardHeader(title = 'Morphine Consumption Explorer', titleWidth = 290),
sidebar = dashboardSidebar(sidebarMenu(menuItem("Plots", tabName = "plots", icon = icon('poll')),
menuItem("Dashboard", tabName = "dash", icon = icon('tachometer-alt')),
menuItem("Prediction", tabName = "pred", icon = icon('search')), id = "menu")),
body = dashboardBody(tags$head(tags$style(HTML('.main-header .logo {font-weight: bold;}'))),
tabItems(
#Plots tab content
tabItem('plots',
#Histogram filter
box(status = 'primary', title = 'Filter for the histogram plot',
selectInput('num', "Numerical variables:", c("Age", "BMI", "IV_Fluids", "Operative_times", "Blood_loss", "Time_to_Aldrete_9", "morphine_consumption_24h1",
"VAS_basalR", "VAS_basalM", "VAS_2hrR", "VAS_2hrM", "VAS_4hrM", "VAS-4hrR",
"VAS_8hrR", "VAS_8hrM", "VAS_12hrR", "VAS_12hrM", "VAS_16hrR", "VAS_16hrM",
"VAS_24hrR", "VAS_24hrM", "QOR_psychological_support", "QOR_emotional_state",
"QOR_Physical_comfort", "QOR_physical_independence", "QOR_Pain", "Total")),
footer = 'Histogram plot for numerical variables'),
#Frequency plot filter
box(status = 'primary', title = 'Filter for the frequency plot',
selectInput('cat', 'Categorical variables:', c("ASA", "Postoperative_vomiting", "Sedation_0to8h", "Sedation_9to16h", "Sedation_17to24h")),
footer = 'Frequency plot for categorical variables'),
#Boxes to display the plots
box(plotOutput('histPlot')),
box(plotOutput('freqPlot'))),
#Prediction tab content
tabItem('pred',
#Filters for categorical variables
box(title = 'Categorical variables',
status = 'primary', width = 12,
splitLayout(
tags$head(tags$style(HTML(".shiny-split-layout > div {overflow: visible;}"))),
cellWidths = c('0%', '19%', '4%', '19%', '4%', '19%', '4%', '19%', '4%', '8%'),
selectInput( 'p_group', 'group', c("0", "30", "60", "90")),
div(),
selectInput('p_ASA', 'ASA', c('1', '2', '3')),
div(),
selectInput( 'p_Sedation_17to24h', 'Ramsey Sedation at 17-24h', c('1', '2', '3', '4')),
div(),
radioButtons( 'p_Postoperative_vomiting', 'PONV', c('Yes', 'No')))),
#Filters for numeric variables
box(title = 'Numerical variables',
status = 'primary', width = 12,
splitLayout(cellWidths = c('22%', '4%','21%', '4%', '21%', '4%', '21%'),
sliderInput( 'p_Age', 'Age (year)', min = 0, max = 100, value = 0),
div(),
numericInput( 'p_BMI', 'BMI', 0),
div(),
numericInput( 'p_VAS_24hrM', 'VAS with Movement at 24hr', 0),
div(),
numericInput( 'p_QOR_psychological_support', 'QOR - Psychological Support', 0),
div(),
numericInput( 'p_QOR_Pain', 'QOR - Pain', 0),
numericInput( 'p_QOR_Physical_comfort', 'QOR - Physical Comfort', 0),
div(),
)),
#Box to display the prediction results
box(title = 'Prediction result',
status = 'success',
solidHeader = TRUE,
width = 4, height = 260,
div(h5('Morphine Consumption (mg):')),
verbatimTextOutput("value", placeholder = TRUE),
div(h5('Range of Morphine Consumption:')),
verbatimTextOutput("range", placeholder = TRUE),
actionButton('cal','Calculate', icon = icon('calculator'))),
#Box to display information about the model
box(title = 'Model explanation',
status = 'success',
width = 8, height = 260,
helpText('The following model will predict the total amount of morphine consumed by age, BMI, Visual Analog Scale at 24 hours with movement, and Quality of Recovery.'),
helpText('The name of the dataset used to train the model is "Short-term efficacy of preoperative Duloxetine for patients subjected to modified radical mastectomy A dose ranging randomized controlled trial", taken from the UCI Machine Learning Repository website. The data contains 17,379 observations and 16 attributes related to time and weather conditions.'),
helpText(sprintf('The prediction is based on a random forest supervised machine learning model. Furthermore, the models deliver a mean absolute error (MAE) of %s morphine consumed, and a root mean squared error (RMSE) of %s total number of morphine consumed.', round(mae_rf, digits = 0), round(rmse_rf, digits = 0)))
))
)
),
title = 'Morphine Consumption Explorer',
skin = "blue")
server <- function(input, output, session) {}
shinyApp(ui, server)

Related

How to create a numericinput widget in Shiny app to add new observations to existing data frame?

sorry if this is repetitive and so simple it is annoying, but I am new to Shiny.
I need help with a shiny app I am trying to create for my golf game. I have loaded a CSV file with previous distance and accuracy observations to Rstudio and completed a script file with what will generally be done: data preprocessing and then visualizations.
I am now struggling with converting that to the app.R file, specifically, how to create a widget where I can add new numeric observations to the current data frame. The end goal is to use the app to log data as I play (practice or an actual round), which updates in real time for quick insight into the average distance and accuracy for each club.
Here is the very basic shiny code I have got to work for the numeric input:
`library(shiny)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Numeric Add Test"),
column(3,
numericInput("num",
h3("Numeric input"),
value = 1,
min = 50,
max = 400,
step = 25))
)
# Define server logic required to draw a histogram
server <- function(input, output) {
}
# Run the application
shinyApp(ui = ui, server = server)`
I have found ways to include an 'add' button to a list, but what I am hoping to do is have the new numeric input be added to the specified variable (club, distance, accuracy) in the referenced dataset. This action would change the existing data, but add to it and grow the dataset over time.
Not sure if this helps for context at all, but below is the script file for preprocessing and visuals I described above:
`######### Golf Data Practice for App #############
## Read in Data set and address the column names starting with a number
Golfdata <- data.frame(read_csv("Shiny Apps/Golf Dataset .csv"))
Golfdata <- as.data.frame(Golfdata)
#Drop the last two columns for only clubs. Then create shot bias DF as well.
Clubs <- Golfdata %>% select(-c(11,12))
ShotBias <- Golfdata %>% select(c(11,12))
#Visualize the Average club distance
##Convert the club df by summarizing each variable by its average,
## then use the gather() to convert to long instead of wide to finally
## prepare the df for visualizing.
ClubAverage <- Clubs %>% summarise_all(mean) %>% gather(ClubAverage) %>%
mutate_if(is.numeric, round, digits = 0)
library(ggplot2)
value <- ClubAverage$value
ggplot(ClubAverage) +
aes(x = fct_reorder(ClubAverage, value, .desc = TRUE), y = value, label = value,
color = ClubAverage) +
geom_col( show.legend = FALSE, fill = "white") +
geom_text(nudge_y = 10, color = "black", size=4, fontface = "bold") +
labs(x = "Club",
y = "Yards", title = "Average Club Distance") +
theme(panel.background = element_rect(fill="forestgreen"),
panel.grid.major.x = element_blank(),
panel.grid.major = element_line(color = "yellow"),
panel.grid.minor = element_line(color = "yellow1")) +
theme(plot.title = element_text(size = 24L,
face = "bold", hjust = 0.5), axis.title.y = element_text(size = 18L, face = "bold"), axis.title.x =
element_text(size = 18L,
face = "bold"))
## Visualize the Average Accuracy ##
## This time, summarize the columns by their mean,
## but keep as wide -- no gather() function needed.
AverageShotBias <- ShotBias %>% summarise_all(mean)
ggplot(AverageShotBias) +
aes(x = Accuracy.Bias, y = Distance.Bias) +
geom_point(shape = "circle filled",
size = 18L, fill = "yellow") +
labs(x = "Accuracy", y = "Distance", title = "Average Shot Bias") +
theme(panel.background = element_rect(fill="forestgreen")) +
theme(plot.title = element_text(size = 24L, face = "bold", hjust = 0.5), axis.title.y =
element_text(size = 14L,
face = "bold"), axis.title.x = element_text(size = 14L, face = "bold")) +
xlim(-1, 1) +
ylim(-1, 1) +
geom_hline(yintercept = 0, size=1) +
geom_vline(xintercept = 0, size=1)`
Something I have found regarding the add button is the code here:
` ,actionButton('add','add')
,verbatimTextOutput('list')
)`
This does create an add button, which after updating the server code does create a list of added inputs, however I would like to be able to adjust the code for adding the observation to the variables in the data set.
I assume I would create an add button for each variable, just need to understand better how to do that.
The structure of your data used in the plot is not clear, but this is how to get the inputs or update dataset using eventReactive or observeEvent in the server. you can read this to learn the difference
server <- function(input, output) {
distance <- eventReactive(input$addButton, {
input$distInput
}, ignoreInit = T, ignoreNULL = F)
accbias <- eventReactive(input$accBiasButton, {
input$accslider
})
distbias <- eventReactive(input$DistBiasButton, {
input$distslider
}, ignoreNULL=F)
output$plot1 <- renderPlot({
input$distInput
mydist <- distance()
# plot
})
output$plot2 <- renderPlot({
input$distInput # use the inputs here
mydist <- distance() # or the reactives
})
}
the two output plots in your code have the same outputId
Follow UP to my Question: I have written the code for the ui, now I am still trying to figure out how to code the server properly so the distance and accuracy numeric inputs can be added to a data frame. That data frame will then be used to create the two visuals.
library(shiny)
library(gridlayout)
library(DT)
library(tidyverse)
ui <- grid_page(
layout = c(
"title title title",
"h1 h2 h3 ",
"h4 h4 h5 "
),
row_sizes = c(
"100px",
"0.86fr",
"1.14fr"
),
col_sizes = c(
"250px",
"0.71fr",
"1.29fr"
),
gap_size = "1rem",
grid_card_text(
area = "title",
content = "My Golf Data",
alignment = "center",
is_title = FALSE
),
grid_card(
area = "h2",
title = "Distance Input",
numericInput(
inputId = "distInput",
label = "Distance",
value = 50L,
min = 50L,
max = 400L,
step = 15L
),
actionButton(
inputId = "addButton",
label = "Add",
width = "100%"
)
),
grid_card(
area = "h1",
title = "Club Select",
radioButtons(
inputId = "clubRadiobuttons",
label = "",
choices = list(
Driver = "D",
`5Wood` = "5W",
`4H` = "4H",
`5I` = "5I",
`6I` = "6I",
`7I` = "7I",
`8I` = "8I",
`9I` = "9I",
PW = "PW",
SW = "SW"
),
width = "100%"
)
),
grid_card(
area = "h3",
title = "Accuracy",
sliderInput(
inputId = "accslider",
label = "Accuracy Bias",
min = -1L,
max = 1L,
value = 0L,
width = "98%",
step = 1L
),
actionButton(
inputId = "accBiasButton",
label = "Add Acc Bias",
width = "100%"
),
sliderInput(
inputId = "distslider",
label = "Distance Bias",
min = -1L,
max = 1L,
value = 0L,
width = "100%",
step = 1L
),
actionButton(
inputId = "DistBiasButton",
label = "Add Dist Bias",
width = "100%"
)
),
grid_card(
area = "h5",
title = "Average Club Distance",
plotOutput(
outputId = "plot",
width = "100%",
height = "400px"
)
),
grid_card(
area = "h4",
title = "Accuracy Average",
plotOutput(
outputId = "plot",
width = "100%",
height = "400px"
)
)
)
server <- function(input, output) {
}
shinyApp(ui, server)

Save and Load user selections based on file selection - RShiny

I am trying to create simple app that acts as a GUI for studying different files having same variables but with different version and content. I am unable to give an app where every time the user opens the app they dont have to enter in their parameters again where they left off. I'd like them to be able to save their parameters and bring them up again when they go back to the app.
I am giving my sample code here, however the number of inputs and plots are far more in the actual app. I want to know if there is any solution to save these dependent inputs and outputs.
library(shiny)
library(pryr)
ui = shinyUI(fluidPage(
# Application title
titlePanel("Example Title"),
# Sidebar structure
sidebarLayout(
sidebarPanel(
textInput("save_file", "Save to file:", value="sample.RData"),
actionButton("save", "Save input value to file"),
uiOutput("load"),
uiOutput("file"),
uiOutput("mytype"),
uiOutput("mysubtype")
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(id="tab",
tabPanel(
"Plot",
plotOutput("distPlot"),
checkboxInput(inputId = "density",
label = strong("Show Adjustment Factors"),
value = FALSE),
conditionalPanel(condition = "input.density == true",
sliderInput(inputId = "bandwidth",
label = "Width adjustment: ",
min = 0.5, max = 4, value = 1, step = 0.1),
radioButtons("mycolor", "Color Adjustment: ",
choices = c(Red = "red", Black = "black", Blue = "blue"),selected = "black", inline = TRUE)
)),
tabPanel("Summary",
h3(textOutput("label")),
verbatimTextOutput("summary")
)
))
)
)
)
server = function(input, output, session) {
# render a selectInput with all RData files in the specified folder
output$load <- renderUI({
choices <- list.files("/home/user/Documents/Shiny/", pattern="*.RData")
selectInput("input_file", "Select input file", choices)
})
# render a selectInput with all csv files in the specified folder so that user can choose the version
output$file <- renderUI({
choices.1 <- list.files("/home/user/Documents/Shiny/", pattern="*.csv")
selectInput("input_csv", "Select csv file", choices.1)
})
# Load a csv file and update input
data = eventReactive(input$input_csv, {
req(input$input_csv)
read.csv(paste0("/home/user/Documents/Shiny/",input$input_csv),
header = TRUE,
sep = ",")
})
#Display Type - Types may differ based on file selection
output$mytype <- renderUI({
selectInput("var1", "Select a type of drink: ", choices = levels(data()$Type))
})
#Display SubType - This would be dependent on Type Selection
output$mysubtype <- renderUI({
selectInput("var2", "Select the SubType: ", choices = as.character(data()[data()$Type==input$var1,"Subtype"]))
})
# Save input when click the button
observeEvent(input$save, {
validate(
need(input$save_file != "", message="Please enter a valid filename")
)
mycolor <- input$mycolor
mytype = input$var1
mysubtype = input$var2
density <- input$density
bandwidth <- input$bandwidth
save(bandwidth, density, mycolor, mytype, mysubtype,
file=paste0("/home/user/Documents/Shiny/", input$save_file))
choices <- list.files("/home/user/Documents/Shiny/", pattern="*.RData")
updateSelectInput(session, "input_file", choices=choices)
choices.1 <- list.files("/home/user/Documents/Shiny/", pattern="*.csv")
updateSelectInput(session, "input_csv", choices=choices.1)
})
# Load an RData file and update input
# input$var1, input$var2, input$density, input$bandwidth, input$mycolor),
observeEvent(c(input$input_file),
{
load(paste0("/home/user/Documents/Shiny/",input$input_file))
updateSelectInput(session, "var1", choices = levels(data()$Type), selected = mytype)
updateSelectInput(session, "var2", choices = as.character(data()[data()$Type==mytype,"Subtype"]), selected = mysubtype)
updateCheckboxInput(session, "density", value = density)
updateSliderInput(session, inputId = "bandwidth", value=bandwidth)
updateRadioButtons(session, "mycolor", choices = c(Red = "red", Black = "black", Blue = "blue"), selected = mycolor, inline = TRUE)
})
output$distPlot <- renderPlot({
# generate plot
x = data()[data()$Type == input$var1 & data()$Subtype == input$var2, c("Alcohol_Content","Price")]
plot(x$Alcohol_Content, x$Price, type = "l", xlab = "Alcohol content", ylab = "Price",
main = "Sample Plot",
col="red",
lwd=1.5)
if (input$density)
plot(x$Alcohol_Content, x$Price, type = "p", xlab = "Alcohol content", ylab = "Price",
main = "Sample Plot",
col=input$mycolor,
lwd=input$bandwidth)
})
output$summary <- renderText(summary(data()))
}
shinyApp(ui, server)
The Input csv files would be always stored in
"/home/user/Documents/Shiny/"
The User could just click "Save to
file:" and it should save the user selections inside "sample.RData"
located in same "/home/user/Documents/Shiny/". Hence I want to give a selectinput where user can choose the .RData file also.
The user should also be able to save the inputs on Mainpanel which they would use to modify the chart
Questions:-
Most of the code works fine given above but how can I save #Display Subtype.
What happens if I add one more dependent list like Type and Subtype?
And also if I can get some help on whether the solution would work for multiple select inputs?.
Any help on the code would be really be appreciated.
Dummy Data:-
x = data.frame(Type=rep(c("WINE"), 9), Subtype=rep(c("TABLE WINE RED", "TABLE WINE WHITE", "MONTILLA"), each=3), Alcohol_content= c(14, 11.5, 12, 11, 13.5, 11, 12.5, 12, 11.5), Price = c(30.99, 32.99, 29.99, 33.99, 36.99, 34.99, 119, 32.99, 13.99))
y = data.frame(Type=rep(c("REFRESHMENT"), 9), Subtype=rep(c("CIDER ALL", "SPIRIT", "BEER"), each=3), Alcohol_content= c(5, 5.2, 7, 5.3, 6.9, 5, 5, 6, 5), Price = c(9.99, 9.99, 8.99, 9.95, 3.49, 9.99, 12.99, 13.49, 21.99))
bcl_data1 = rbind(x, y)
write.csv(bcl_data1, "bcl_data1.csv")
There are many more Subtypes under each Type (Wine , Refreshment). I am somehow not able to retrieve the Subtype value through above code, However when I load Sample.RData I can see var2 = my selected value.
I would like to know how save these values please.
Here is a working version of your code. Your problem was the concurrent use of renderUI and updateSelectInput. Everytime you tried to update your selectInput it was re-rendered right away so that the change wasn't visible.
I'd recommend to render the selectInput's in the UI (which I did for "var2") and use updateSelectInput only. (If you really want to continue building your own bookmarks.)
Best regards
library(shiny)
library(pryr)
if(!file.exists("bcl_data1.csv")){
x = data.frame(Type=rep(c("WINE"), 9), Subtype=rep(c("TABLE WINE RED", "TABLE WINE WHITE", "MONTILLA"), each=3), Alcohol_content= c(14, 11.5, 12, 11, 13.5, 11, 12.5, 12, 11.5), Price = c(30.99, 32.99, 29.99, 33.99, 36.99, 34.99, 119, 32.99, 13.99))
y = data.frame(Type=rep(c("REFRESHMENT"), 9), Subtype=rep(c("CIDER ALL", "SPIRIT", "BEER"), each=3), Alcohol_content= c(5, 5.2, 7, 5.3, 6.9, 5, 5, 6, 5), Price = c(9.99, 9.99, 8.99, 9.95, 3.49, 9.99, 12.99, 13.49, 21.99))
bcl_data1 = rbind(x, y)
write.csv(bcl_data1, "bcl_data1.csv")
}
settings_path <- getwd()
# settings_path <- "/home/user/Documents/Shiny/"
ui = shinyUI(fluidPage(
# Application title
titlePanel("Example Title"),
# Sidebar structure
sidebarLayout(
sidebarPanel(
textInput("save_file", "Save to file:", value="sample.RData"),
actionButton("save", "Save input value to file"),
p(),
p(),
uiOutput("load"),
uiOutput("file"),
uiOutput("mytype"),
selectInput("var2", "Select the SubType: ", choices = NULL)
),
# Show a plot of the generated distribution
mainPanel(
tabsetPanel(id="tab",
tabPanel(
"Plot",
plotOutput("distPlot"),
checkboxInput(inputId = "density",
label = strong("Show Adjustment Factors"),
value = FALSE),
conditionalPanel(condition = "input.density == true",
sliderInput(inputId = "bandwidth",
label = "Width adjustment: ",
min = 0.5, max = 4, value = 1, step = 0.1),
radioButtons("mycolor", "Color Adjustment: ",
choices = c(Red = "red", Black = "black", Blue = "blue"),selected = "black", inline = TRUE)
)),
tabPanel("Summary",
h3(textOutput("label")),
verbatimTextOutput("summary")
)
))
)
)
)
server = function(input, output, session) {
# render a selectInput with all RData files in the specified folder
last_save_path <- file.path(settings_path, "last_input.backup")
if(file.exists(last_save_path)){
load(last_save_path)
if(!exists("last_save_file")){
last_save_file <- NULL
}
} else {
last_save_file <- NULL
}
if(!is.null(last_save_file)){
updateTextInput(session, "save_file", "Save to file:", value=last_save_file)
}
output$load <- renderUI({
choices <- list.files(settings_path, pattern="*.RData")
selectInput("input_file", "Select input file", choices, selected = last_save_file)
})
# render a selectInput with all csv files in the specified folder so that user can choose the version
output$file <- renderUI({
choices.1 <- list.files(settings_path, pattern="*.csv")
selectInput("input_csv", "Select csv file", choices.1)
})
# Load a csv file and update input
csv_data = eventReactive(input$input_csv, {
req(input$input_csv)
read.csv(file.path(settings_path,input$input_csv),
header = TRUE,
sep = ",")
})
#Display Type - Types may differ based on file selection
output$mytype <- renderUI({
req(csv_data())
selectInput("var1", "Select a type of drink: ", choices = unique(csv_data()$Type))
})
#Display SubType - This would be dependent on Type Selection
observeEvent(input$var1, {
req(csv_data())
req(input$var1)
updateSelectInput(session, "var2", "Select the SubType: ", choices = as.character(csv_data()[csv_data()$Type==input$var1,"Subtype"]), selected = isolate(input$var2))
})
# Save input when click the button
observeEvent(input$save, {
validate(
need(input$save_file != "", message="Please enter a valid filename")
)
last_save_file <- input$save_file
save(last_save_file, file=last_save_path)
mycolor <- input$mycolor
mytype = input$var1
mysubtype = input$var2
density <- input$density
bandwidth <- input$bandwidth
save(bandwidth, density, mycolor, mytype, mysubtype,
file=file.path(settings_path, input$save_file))
})
# Load an RData file and update input
observeEvent(input$input_file, {
req(input$input_file)
load(file.path(settings_path, input$input_file))
updateSelectInput(session, "var1", choices = unique(csv_data()$Type), selected = mytype)
updateSelectInput(session, "var2", choices = mysubtype, selected = mysubtype)
updateCheckboxInput(session, "density", value = density)
updateSliderInput(session, "bandwidth", value = bandwidth)
updateRadioButtons(session, "mycolor", choices = c(Red = "red", Black = "black", Blue = "blue"), selected = input$mycolor)
})
output$distPlot <- renderPlot({
req(csv_data())
req(input$var1)
req(input$var2)
# generate plot
x = csv_data()[csv_data()$Type == input$var1 & csv_data()$Subtype == input$var2, c("Alcohol_content", "Price")]
if(nrow(x) > 0){
x <- x[order(x$Alcohol_content), ]
plot(x$Alcohol_content, x$Price, type = "l", xlab = "Alcohol content", ylab = "Price",
main = "Sample Plot",
col="red",
lwd=1.5)
if (input$density)
plot(x$Alcohol_content, x$Price, type = "p", xlab = "Alcohol content", ylab = "Price",
main = "Sample Plot",
col=input$mycolor,
lwd=input$bandwidth)
}
})
output$summary <- renderText(summary(csv_data()))
}
shinyApp(ui, server)

How to add tooltips to html widgets in shiny dashboard

I am struggling to add tooltips to html widgets in Rshiny. bs_embed_tooltip from library(flexdashboard) does the job for some shiny widgets but returns the following error when it is applied to an html widget:
Error in .tag_validate(.) :
tag is not a shiny.tag - tag must be generated using htmltools or shiny
Here is my minimal working example (modifying example code from shinydashboard):
## app.R ##
library(shinydashboard)
library(flexdashboard)
library(bsplus) # For shiny tooltips
ui <- dashboardPage(
dashboardHeader(title = "Basic dashboard"),
dashboardSidebar(),
dashboardBody(
# Boxes need to be put in a row (or column)
fluidRow(
box(plotOutput("plot1", height = 250) %>%
bs_embed_tooltip("This is the output chart.", placement = 'bottom')
),
box(title = "Controls",
sliderInput("slider", "Number of observations:", 1, 100, 50) %>%
bs_embed_tooltip("Use this slider to select the number of observations.", placement = 'bottom')
),
box(title = "Guage",
gaugeOutput("guage_value") # %>% bs_embed_tooltip("This gauge shows the input value from the slider.", placement = 'bottom')
)
)
)
)
server <- function(input, output) {
set.seed(122)
histdata <- rnorm(500)
output$plot1 <- renderPlot({
data <- histdata[seq_len(input$slider)]
hist(data)
})
output$guage_value <- renderGauge({
gauge(input$slider, min = 0, max = 100, symbol = '', gaugeSectors(
danger = c(0, 30), warning = c(31, 70), success = c(71, 100) ))
})
}
shinyApp(ui, server)
Your help to get around the code in the comment would be much appreciated.
Try with this new box for the gauge-box:
box(title = "Guage",
gaugeOutput("guage_value"),
bsTooltip(id = "guage_value", title = "This gauge shows the input value from the slider.", placement = "bottom")
)

R Shiny App working locally but not on shinyapps.io

I have seen that this problem has happened to other people, but their solutions have not worked for me. I have my app.R file and a .RData file with the required inputs in the same ECWA_Strategic_Planning_Tool directory. When I run:
library(rsconnect)
rsconnect::deployApp('C:/Users/mikialynn/Documents/Duke/Spring2017/MP/GISTool/Final/ECWA_Strategic_Planning_Tool')
I get the following error on the web page that opens up:
ERROR: An error has occurred. Check your logs or contact the app author for clarification.
However, I cannot find anything wrong. I install all of my packages, I use relative pathways etc. I am pasting all of the code from my app below. If anyone can spot what I'm doing wrong, I would greatly appreciate it!
library(shiny)
library(leaflet)
library(sp)
library(rgdal)
library(rstudioapi) # For working directory
library(raster)
library(RColorBrewer)
library(rgeos) #Maybe use gSimplify to simplify polygon
library(DT) #To make interactive DataTable
library(plotly) #For pie chart
library(ggplot2) # for layout
# Set Working Directory
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
# Load R Workspace
load('Shiny.Strategies.RData')
# UI variables
neigh.names <- levels(merge.proj$View)
neigh.default <- c("Urban7")
dt.names <- c('PARCEL_ID', 'PIN', 'OWNER_NAME', 'SITE_ADDRE', 'OWNER_ADDR',
'SUM_ACRE', 'LANDUSE_DE', 'LAND_VALUE', 'TOTAL_VALU', 'SALE_PRICE',
'Pluvial_WtScore', 'Rest_WtScore', 'GI_WtScore', 'SC_WtScore',
'UNCWI_WtScore', 'Total_Score', 'View')
dt.default <- c('PARCEL_ID', 'Pluvial_WtScore', 'Rest_WtScore',
'GI_WtScore', 'SC_WtScore', 'UNCWI_WtScore', 'Total_Score', 'View')
# Build UI
ui <- fluidPage(
titlePanel("ECWA Strategic Planning Tool"),
HTML('<br>'),
column(2,
HTML("<strong>Instructions:</strong><br/><br/>"),
HTML("<p>1) Select weights for parameters and click 'Run' to
initiate tool.<br/><br/>
2) Use rightside panel to adjust Table and Map Settings.<br/>
<br/>
3) Use search/sort functions of Table to identify parcels.
Select row to display Total Score Chart.<br/><br/>
4) Input View and Parcel ID from Table to Map settings to
identify parcel in Map.<br/><br/>
5) When satisfied with weights, click 'Export Shapefile' to
save shapefile of all parcels.<p/><br/>"),
HTML("<strong>Calculate Parcel Scores: </strong><br/>"),
helpText('The sum of the weights must equal to 1.'),
sliderInput(inputId = "weightPluvial", label = "Weight for Pluvial
Flooding",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightRest", label = "Weight for
Restoration",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightGI", label = "Weight for Green
Infrastructure",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightSC", label = "Weight for City
Stormwater Controls",
value = 0.20, min = 0, max = 1),
sliderInput(inputId = "weightUNCWI", label = "Weight for UNCWI",
value = 0.20, min = 0, max = 1),
actionButton("run", "Run"),
actionButton("export", "Export Shapefile")),
column(8,
HTML("<h3><strong>Table Summary</strong></h3>"),
HTML("<br>"),
dataTableOutput("table")),
column(2,
HTML("<p><br><br></p>"),
HTML("<h4>Table Settings:</h4>"),
checkboxGroupInput(inputId = 'show_vars', label = 'Select column(s)
to display in Table:', choices = dt.names, selected = dt.default),
HTML("<strong>Total Score Chart:</strong>"),
helpText("Please select Table row to display pie chart."),
plotlyOutput("pie")
),
fluidRow(
column(8, offset = 2,
HTML("<br>"),
HTML("<h3><strong>Map Display</strong></h3>"),
leafletOutput("map", height = 800),
HTML("<br><br>")),
column(2,
HTML("<p><br><br><br></p>"),
HTML("<h4>Map Settings:</h4>"),
checkboxGroupInput(inputId = 'show_neigh', label = 'Select
View(s) to display in Map:', choices = neigh.names,
selected = neigh.default),
HTML("<br>"),
sliderInput("range", "Select score range to display in Map:", min
= 0.0, max= 10.0, value = as.numeric(c("0.0", "10.0")), step = 0.1),
HTML("<br>"),
HTML("<strong>Parcel Zoom:</strong>"),
helpText("The View and Score Range must contain the parcel of
interest to execute zoom."),
numericInput('parcel','Enter Parcel ID',0)
)
))
# SERVER
server <- function(input, output) {
defaultData <-
eventReactive(input$run, {
# Multiply by Weights
merge.proj#data$Pluvial_WtScore <-
round(merge.proj#data$Pluvial_Score*input$weightPluvial, digits = 1)
merge.proj#data$Rest_WtScore <-
round(merge.proj#data$Rest_Score*input$weightRest, digits = 1)
merge.proj#data$GI_WtScore <-
round(merge.proj#data$GI_Score*input$weightGI, digits = 1)
merge.proj#data$SC_WtScore <-
round(merge.proj#data$SC_Score*input$weightSC, digits = 1)
merge.proj#data$UNCWI_WtScore <-
round(merge.proj#data$UNCWI_Score*input$weightUNCWI, digits = 1)
# Find Total Score
merge.proj#data$Total_Score <- merge.proj#data$Pluvial_WtScore +
merge.proj#data$Rest_WtScore + merge.proj#data$GI_WtScore +
merge.proj#data$SC_WtScore + merge.proj#data$UNCWI_WtScore
return(merge.proj)
})
# Subset by neighborhood
neighData <- reactive ({
merge.proj <- defaultData()
merge.proj[merge.proj$View%in%input$show_neigh,]
})
# Plot with leaflet
# Palette for map
colorpal <- reactive({
merge.proj <- neighData()
colorNumeric(palette = "YlOrRd",
domain = merge.proj$Total_Score)
})
# Pop Up Option for map
# popup <- paste0("<strong>Parcel ID: </strong>",
# merge.proj#data$PARCEL_ID,
# "<br><strong>Total Score: </strong>",
# merge.proj#data$Total_Score)
# Label Option for map
labels <- reactive({
merge.proj <- neighData()
sprintf("<strong>Parcel ID: </strong>%s<br/><strong>Total Score:
</strong>%g",
merge.proj$PARCEL_ID,
merge.proj$Total_Score) %>% lapply(htmltools::HTML)
})
# Render Default Map
output$map <- renderLeaflet ({
merge.proj <- neighData()
pal <- colorpal()
lab <- labels()
leaflet() %>%
#addProviderTiles(provider='Esri.WorldImagery') %>%
# setView(zoom =) %>%
addTiles() %>%
addPolygons(
#data = merge.proj[input$show_neigh,, drop = FALSE],
data=merge.proj,
fillColor = ~pal(Total_Score),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 3,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
# popup= popup) %>%
label = lab,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto")) %>%
addLegend(position = "bottomleft",pal = pal, opacity = 0.7, values =
merge.proj$Total_Score, title = "<strong>Total Score</strong>")
})
# Build Data Table
output$table <- renderDataTable({
merge.proj <- defaultData()
table.dat <- merge.proj[, c('PARCEL_ID', 'PIN', 'OWNER_NAME',
'SITE_ADDRE', 'OWNER_ADDR', 'SUM_ACRE', 'LANDUSE_DE', 'LAND_VALUE',
'TOTAL_VALU', 'SALE_PRICE', 'Pluvial_WtScore', 'Rest_WtScore', 'GI_WtScore',
'SC_WtScore', 'UNCWI_WtScore', 'Total_Score', 'View')]
datatable(data = table.dat#data[, input$show_vars, drop = FALSE],
options = list(lengthMenu = c(5, 10, 20, 30), pageLength = 20), rownames =
FALSE)
})
# Plot-ly
output$pie <- renderPlotly({
merge.proj <- defaultData()
names <- c('Pluvial', 'Rest', 'GI', 'SC', 'UNCWI')
colors <- c('rgb(128,133,133)', 'rgb(211,94,96)', 'rgb(144,103,167)',
'rgb(114,147,203)', 'rgb(171,104,87)')
selectedrowindex <-
input$table_rows_selected[length(input$table_rows_selected)]
selectedrowindex <- as.numeric(selectedrowindex)
df <- data.frame(merge.proj[selectedrowindex, c('Pluvial_WtScore',
'Rest_WtScore', 'GI_WtScore', 'SC_WtScore', 'UNCWI_WtScore')])
vector <- unname(unlist(df[1,]))
if (!is.null(input$table_rows_selected)) {
par(mar = c(4, 4, 1, .1))
plot_ly(labels = names, values = vector, type = 'pie',
textposition = 'inside',
textinfo = 'label+percent',
insidetextfont = list(color = '#FFFFFF'),
hoverinfo = 'text',
text = ~paste('Score:', vector),
marker = list(colors = colors,
line = list(color = '#FFFFFF', width = 1)),
#The 'pull' attribute can also be used to create space between the sectors
showlegend = FALSE) %>%
layout(#title = '% Total Score',
xaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE),
yaxis = list(showgrid = FALSE, zeroline = FALSE, showticklabels = FALSE))
}
else {return(NULL)}
})
# Update map to parcel score slider
# Subset data
filteredData <- reactive({
merge.proj <- neighData()
merge.proj[merge.proj#data$Total_Score >= input$range[1] &
merge.proj#data$Total_Score <= input$range[2],]
})
# New Palette
colorpal2 <- reactive({
merge.proj <- filteredData()
colorNumeric(palette = "YlOrRd",
domain = merge.proj$Total_Score)
})
# Pop Up Option
# popup <- paste0("<strong>Parcel ID: </strong>",
# merge.proj#data$PARCEL_ID,
# "<br><strong>Total Score: </strong>",
# merge.proj#data$Total_Score)
# Label Option
labels2 <- reactive({
merge.proj <- filteredData()
sprintf("<strong>Parcel ID: </strong>%s<br/><strong>Total Score:
</strong>%g",
merge.proj$PARCEL_ID,
merge.proj$Total_Score) %>% lapply(htmltools::HTML)
})
#Leaflet Proxy
observe({
merge.proj <- filteredData()
pal2 <- colorpal2()
lab2 <- labels2()
leaf <- leafletProxy("map", data = filteredData()) %>%
clearShapes() %>%
addPolygons(
fillColor = ~pal2(Total_Score),
weight = 1,
opacity = 1,
color = "white",
dashArray = "3",
fillOpacity = 0.7,
highlight = highlightOptions(
weight = 3,
color = "#666",
dashArray = "",
fillOpacity = 0.7,
bringToFront = TRUE),
# popup= popup) %>%
label = lab2,
labelOptions = labelOptions(
style = list("font-weight" = "normal", padding = "3px 8px"),
textsize = "15px",
direction = "auto"))
if(input$parcel>0){
sub.dat <- merge.proj[merge.proj$PARCEL_ID==input$parcel,]
zx <- mean(extent(sub.dat)[1:2])
zy <- mean(extent(sub.dat)[3:4])
leaf <- leaf %>%
setView(lng=zx,lat=zy,zoom=16)
}
leaf
})
#Update Legend
observe({
proxy <- leafletProxy("map", data = filteredData())
pal2 <- colorpal2()
proxy %>% clearControls()
proxy %>% addLegend(position = "bottomleft",pal = pal2, opacity = 0.7,
values = ~Total_Score, title = "<strong>Total Score</strong>")
})
# Export new shapefile
#make so that user can choose name and allow overwrite
observeEvent(input$export, {
merge.proj <- defaultData()
writeOGR(merge.proj, dsn = "Data", layer = "Strategies_Output", driver =
"ESRI Shapefile")
})
}
shinyApp(ui = ui, server = server)
Issue resolved! My initial suspicion was correct; it had to do with the .rdata file. It also relates to shinyapp.io's servers which run on a Linux based server. From my reading, Linux only handles lowercase file paths and extensions. The reason why it worked for the .csv file is because it's pretty common to have the file extension saved in all lowercase. This was not the case for the .RData file. Using the RStudio IDE and the physical "Save Workspace" button, the default file extension is .RData (case sensitive). I couldn't rename the file extension (for some reason, I'm not the most tech-savvy person). Similar to the load() function, there's the save() function. Previously, I used the save() file as follows (note the capitalized .RData at the end):
save(df_training_separated_with_models, file = "sample_data_with_models.RData")
However, using the same function in all lowercase fixes the issue:
save(df_training_separated_with_models, file = "sample_data_with_models.rdata")
Hope this helps any other poor soul with the same issue that is scouring the internet and other forums.
Cheers!

Trying to subset in the Plotly call using Shiny input still plots on full data frame

The following code works to an extent - it plots a graph, but it is very clearly not subsetting the original data frame, but plotting based on all the indicators, years etc. Any thoughts on why? I have tried wrapping in reactive, using select(filter from dplyr, using "" around the input$indicator etc. I have spent about 4 hours looking through various suggestions on here, Plotly and Shiny sites, without a solution. Starting to doubt I'll ever get the hang of this.
#
# This is a Shiny web application. You can run the application by clicking
# the 'Run App' button above.
#
library(dplyr)
library(shiny)
library(fingertipsR)
library(viridis)
library(plotly)
#Import QOF indicators
setwd("/Users/ianbowns/Documents/R/ShinyFT")
dat <- readRDS("data")
my.df <- as.data.frame(dat)
# Define UI for application that draws boxplot
ui <- fluidPage(
# Application title
titlePanel("FingerTips QOF Prevalences"),
# Input for year, area and indicator
sidebarLayout(
sidebarPanel(
selectInput(inputId = "indicator",
label = "Choose indicator:",
choices = levels(my.df$IndicatorName),
selected = "Hypertension: QOF prevalence (all ages)"),
selectInput(inputId = "areatype",
label = "Type of area:",
choices = levels(my.df$AreaType),
selected = "County & UA"),
selectInput(inputId = "year",
label = "Choose a year:",
choices = levels(my.df$Timeperiod),
selected = "2015/16")),
# Show a plot of the generated distribution
mainPanel(
plotlyOutput("bPlot", height = 500, width = 1000)
)
))
# Define server logic required to draw a histogram
server <- function(input, output) {
# draw the boxplot
output$bPlot <- renderPlotly({
plot_ly(data = subset(my.df, my.df$IndicatorName ==
input$indicator & my.df$AreaType == input$areatype &
my.df$Timeperiod == input$year), y = my.df$Value, color
= my.df$ParentName, type = "box",
colors = viridis_pal(alpha = 1, begin = 0, end = 1,
direction = -1, option = "D")(3)) %>%
layout(title = input$indicator, titlefont = list(family
= "Helvetica", size = 16),
xaxis = list(type = "category", tickfont = list(family =
"Helvetica", size = 8)),
yaxis = list(title = "Prevalence (%)", titlefont =
list(family = "Helvetica", size = 12)))})
}
# Run the application
shinyApp(ui = ui, server = server)