shiny app with own function - r

I want to implement a function in a Shiny app. My own function get_calculate() has the arguments data and tolerance as input and retruns a list with a data.frame and a plot.
I want to show the output depending on tolerance. In my server function I use reactive() to run get_calculate() but it doesn't work.
If I write in renderPlot() and renderDataTable() get_calculate() works.
For large datasets, however, it's inefficient because Shiny will have to run get_calculate() twice.
library(shiny)
library(shinydashboard)
library(foreign)
#load my own function
source("01-get_calculate.R")
ui <- dashboardPage(
dashboardHeader(title = "Analysis"),
dashboardSidebar(
sidebarMenu(
menuItem("Load data", tabName = "data", icon = icon("database")),
menuItem("Mainboard", tabName = "Mainboard", icon = icon("dashboard"))
)
),
dashboardBody(
tabItems(
tabItem(tabName = "data",
fileInput("datafile", "Choose file",
accept = c("text/csv/rds/dbf", 'text/comma-separated-values,text/plain')),
dataTableOutput("mytable")
),
tabItem(tabName = "Mainboard",
fluidRow(
box(
title = "Input", status = "primary", solidHeader = TRUE, collapsible = TRUE,
sliderInput(inputId = "tol",
label = "Tolerance",
value = 4, min = 1, max = 15, step = 1)
)),
fluidRow(
box(
title = "Adherence Curve", status = "warning", solidHeader = TRUE, collapsible = TRUE,
plotOutput("plot_kpm")
),
box(
title = "Overview Table", status = "primary", solidHeader = TRUE, collapsible = TRUE,
tableOutput("table_kpm")
)
)
)
)
)
)
server <- function(input, output) {
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
return(NULL)
}
read.dbf(infile$datapath)
})
output$mytable <- renderDataTable({
filedata()
})
**test <- reactive({
get_calculate(filedata(), tolerance = input$tol)
})
output$plot_kpm <- renderPlot({
test$kpm_chart
})
output$table_kpm <- renderDataTable({
test$data_kpm[, c("Time", "numbers", "Percent")]
})**
}
shinyApp(ui = ui, server = server)

The error you mentioned is most likely from renderDataTable where you are trying to pick couple of columns from test$data_kpm. Check the dataframe for exact column names.

This version of my shiny app runs. But it' ineffcient because shiny have to runs get_calculate twice.
server <- function(input, output) {
#This function is repsonsible for loading in the selected file
filedata <- reactive({
infile <- input$datafile
if (is.null(infile)) {
# User has not uploaded a file yet
return(NULL)
}
read.dbf(infile$datapath)
})
output$mytable <- renderDataTable({
filedata()
})
output$plot_kpm <- renderPlot({
get_calculate(filedata(), tolerance = input$tol)$kpm_chart
})
output$table_kpm <- renderTable({
get_calculate(filedata(), tolerance = input$tol)$data_kpm[, c("Time", "Percent", "Patients")]
})
output$download_mainboard_adherence_table <- downloadHandler(
filename = paste("adherence_table", '.csv', sep=''),
content = function(file) {
write.csv(get_calculate(filedata(), tolerance = input$tol)$data_kpm[, c("Time", "Percent", "Patients")], file)
}
)
}

Why don't you use a reactive expression to run your get_calculate just once ? And then use the result in your output$plot_kpm and output$table_kpm ?
This will optimize your code.

Related

How to create a button that will create a pdf file of a table

I currently have a table being generated and I would like the user to be able to create a pdf file when they click the download button.
I am currently getting an error where when I click the download button I get an html file that downloads the entire page of the app. I thought that using pdf(file) would work but it ignores the function.
Here is currently what I have.
library(shiny)
library(xlsx)
library(shinyWidgets)
population <- read.xlsx("population.xlsx", 1)
fieldsMandatory <- c("selectedCountry")
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
appCSS <-
".mandatory_star {color: red;}"
ui <- fluidPage(
navbarPage(title = span("Spatial Tracking of COVID-19 using Mathematical Models", style = "color:#000000; font-weight:bold; font-size:15pt"),
tabPanel(title = "Model",
sidebarLayout(
sidebarPanel(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
div(
id = "dashboard",
pickerInput(
inputId = "selectedCountry",
labelMandatory ("Country"),
choices = population$Country,
multiple = FALSE,
options = pickerOptions(
actionsBox = TRUE,
title = "Please select a country")
),
sliderInput(inputId = "agg",
label = "Aggregation Factor",
min = 0, max = 50, step = 5, value = 10),
actionButton("go","Run Simulation"),
)
),
mainPanel(
tabsetPanel(
tabPanel("Input Summary", verbatimTextOutput("summary"),
tableOutput("table"),
downloadButton(outputId = "downloadSummary", label = "Save Summary"))
)
)
)
)
)
)
server <- function(input, output, session){
observeEvent(input$resetAll, {
shinyjs::reset("dashboard")
})
values <- reactiveValues()
values$df <- data.frame(Variable = character(), Value = character())
observeEvent(input$go, {
row1 <- data.frame(Variable = "Country", Value = input$selectedCountry)
row2 <- data.frame(Variable = "Aggregation Factor", Value = input$agg)
values$df <- rbind(row1, row2)
})
output$table <- renderTable(values$df)
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "go", condition = mandatoryFilled)
})
output$downloadSummary <- downloadHandler(
filename = function(file) {
paste('my-report.pdf', )
},
content = function(file) {
pdf(file)
}
)
}
shinyApp(ui,server)
Here's a minimal example:
library(shiny)
ui <- fluidPage(
downloadButton("savepdf", "Save pdf")
)
server <- function(input, output, session) {
output$savepdf <- downloadHandler(
filename = "test.pdf",
content = function(file) {
pdf(file)
plot(iris$Sepal.Length, iris$Sepal.Width)
dev.off()
}
)
}
shinyApp(ui, server)
Also see here.
Here is a minimal example with the package latexpdf. It will create the pdf table in the folder of the app.
library(shiny)
library(latexpdf)
dat <- head(iris, 5)
ui <- fluidPage(
br(),
actionButton("dwnld", "Create pdf"),
tableOutput("mytable")
)
server <- function(input, output, session){
output[["mytable"]] <- renderTable({
dat
})
observeEvent(input[["dwnld"]], {
as.pdf(dat)
})
}
shinyApp(ui, server)

R-Shiny: Select input reactive on file input

I am very new to Shiny and am not sure if I am doing this remotely correct/completely oversimplified. I am trying to pull the column headers from an excel fileInput into a selectInput drop down box.
So essentially I would like the options for the select box be determined by the headers of the file input. Then it would link into my equation in the server, which would perform the calculation based on the dataset in the column (the bit in the server with input$col).
I appreciate any comments/answers,
Thanks
EDIT: at a guess, would I need to use uiOutput and renderUI??
ui
ui <- fluidPage(theme = shinytheme(),
setBackgroundColor("white"),
titlePanel(img(src = "image.png", height = 125, width = 450)),
(h1("review app", style = "color:#337ab7")),
p("Calculate"),
headerPanel(h3("Input data here", style = "color:#337ab7")),
sidebarLayout(
sidebarPanel( position =c("left"), style = "color:#337ab7",
numericInput("SL",
"SL", 1, min=1, max=10),
numericInput("LT", "LT",0, min=0, max = 52),
fileInput("file1", 'choose file',
accept = c(".xlsx") ),
selectInput("col", "Column", choices = unique(colnames(input$file1)
)),
checkboxInput("smooth", "Clean my data", value = FALSE, width = NULL),
actionButton("action_Calc", label = "Refresh & Calculate", icon("redo"),
style="color: #fff; background-color: #337ab7; border-color: #2e6da4"),
),
mainPanel(
tabsetPanel(
tabPanel("SS", h1(textOutput("SS"), style = "color:#337ab7")),
tabPanel("guide", img(src = "guide.png", height = 200, width = 600)),
tabPanel("Mydata", div(tableOutput('contents'), style="font-size:55%"))
))))
server
server <- function(input, output) {
Data <- reactive({
req(input$file1)
inFile <- input$file1
read_excel(inFile$datapath, 1)
})
output$contents <- renderTable(bordered = TRUE, style= "border-color:#337ab7", hover = TRUE, {
Data()
})
values<- reactiveValues()
observe({
input$action_Calc
values$int<- isolate({ if (input$smooth) (round( input$SL*sqrt(input$LT/4)*sd( tsclean(Data()[[input$col]],
replace.missing = TRUE, lambda = NULL)) , digits= 2))
else (round( input$SL*sqrt(input$LT/4)*sd(Data()[[input$col]]), digits = 2)) })})
output$SS <- renderText({paste("Calculated is", values$int)} )
}
shinyApp(ui, server)
updatedSelectInput should do it for you. Below is a minimal example.
To reduce package dependencies I switched to loading .csv rather than .xlsx. Note that the loaded file isn't validated, so if junk goes in you'll get junk out.
library(shiny)
#UI
ui <- fluidPage(
selectInput('mydropdown', label = 'Select', choices = 'No choices here yet'),
fileInput('myfileinput', label = 'Select File', accept = c(".csv"))
)
#Server
server <- function(input, output, session) {
observeEvent(input$myfileinput, {
mytable <- read.csv(input$myfileinput$datapath)
updateSelectInput(session, "mydropdown", label = "Select", choices = colnames(mytable))
})
}
shinyApp(ui = ui, server = server)

make conditionalPanel appears when RData file is loaded in shinydashboard

I am making a shiny app that interacts with a big data.frame that I have stored as an RData file. I want the user to select the file, and once the RData is completely loaded (takes ~15 seconds) a second panel should show up allowing the user to input some sample name and do some operations.
Here is how my app looks now
header <- dashboardHeader(title="Analysis and database")
sidebar <- dashboardSidebar(
useShinyjs(),
sidebarUserPanel(),
hr(),
sidebarMenu(
# Setting id makes input$tabs give the tabName of currently-selected tab
id = "sidebarmenu",
menuItem("Analyse old data by Sample", tabName="oldfile", icon = icon("table"), startExpanded = FALSE),
fileInput(inputId = "file1", "Choose database file"),
conditionalPanel(
#condition = "input.sidebarmenu === 'oldfile'",
condition = "output.fileUploaded == 'true' ",
textInput(inputId = "sample", label ="Type a sample ID"),
actionButton("go2", "Filter")
)
)
)
body <- dashboardBody(
tags$style(type="text/css",
".shiny-output-error { visibility: hidden; }",
".shiny-output-error:before { visibility: hidden; }"),
tabItems(
tabItem("oldfile", "Sample name data.table",
fluidRow(DT::dataTableOutput('tabla_oldfile') %>% withSpinner(color="#0dc5c1")))
)
)
ui <- dashboardPage(header, sidebar, body)
### SERVER SIDE
server = function(input, output, session) {
options(shiny.maxRequestSize=100000*1024^2)
prop <- reactive({
if (input$go2 <= 0){
return(NULL)
}
result <- isolate({
if (is.null(input$file1))
return(NULL)
if (is.null(input$sample))
return(NULL)
inFile <- input$file1
print(inFile$datapath)
#big_df <- load(inFile$datapath)
print (big_df)
print(input$sample)
oldtable <- big_df1 %>% filter_at(vars(GATK_Illumina.samples:TVC_Ion.samples),
any_vars(stringi::stri_detect_fixed(., as.character(input$sample))))
oldtable
})
result
})
output$fileUploaded <- reactive({
return(!is.null(prop()))
})
outputOptions(output, 'fileUploaded', suspendWhenHidden=FALSE)
output$tabla_oldfile <- DT::renderDataTable({
DT::datatable(prop(),
filter = 'top',
extensions = 'Buttons',
options = list(
dom = 'Blftip',
buttons =
list('colvis', list(
extend = 'collection',
buttons = list(list(extend='csv',
filename = 'results'),
list(extend='excel',
filename = 'results'),
list(extend='pdf',
filename= 'results')),
text = 'Download'
)),
scrollX = TRUE,
pageLength = 5,
lengthMenu = list(c(5, 15, -1), list('5', '15', 'All'))
), rownames = FALSE
)
})
}
shinyApp(ui, server)
I have used the solution provide in Make conditionalPanel depend on files uploaded with fileInput but I can't make it work, there is another implementation using shinyjs package but don't know how to use it on my example

Upload a csv file with actionbutton and display a corrplot

I tried to make a web application with R::shiny but I met a problem with a piece of code. Indeed, I would like to upload a csv file and display a correlogram.
I tried to set up the correlogram with the actionbutton() followed by the updateSelectizeInput()
However an error has been occured :
Error: Unsupported index type: NULL
Anybody have a solution ? thanks
NB - I don't want to use the fileInput widget to upload the csv file ! Only by the actionbutton !
library(shiny)
library(readr)
library(corrplot)
library(DT)
# File used for the example
data(iris)
write.csv(x = iris, file = "iris.csv")
#UI
ui <- shinyUI(
fluidPage(
navbarPage(
id = "navbar",
tabPanel(
title = "UPLOAD",
br(),
actionButton(inputId = "file", label = "ADD A FILE")
)
)
)
)
#SERVER
server <- function(input, output, session) {
path <- reactiveValues(pth = NULL)
file.choose2 <- function(...) {
pathname <- NULL;
tryCatch({
pathname <- file.choose();
}, error = function(ex) {
})
pathname;
}
observeEvent(input$file,{
path$pth <- file.choose2()
})
observeEvent(input$file, {
newvalue <- "B"
updateNavbarPage(session, "navbar", newvalue)
})
data <- reactive({
df <- readr::read_csv(file = path$pth)
return(df)
})
observeEvent(input$file, {
appendTab(
inputId = "navbar",
tabPanel(
value = "B",
title = "Corr",
sidebarLayout(
sidebarPanel(
selectizeInput(
inputId = "select04",
label = "Select features",
choices = NULL,
multiple = TRUE)
),
mainPanel(
plotOutput(
outputId = "corrplot01", height = "650px")
)
)
)
)
}, once = TRUE)
# I suppose there is a problem with this line
observeEvent(input$select04, {
col <- names(data())
col.num <- which(sapply(data(), class) == "numeric")
col <- col[col.num]
updateSelectizeInput(session = session, inputId = "select04", choices = col)
})
output$corrplot01 <- renderPlot({
df <- data()
df1 <- df[,input$select04]
corr <- cor(x = df1, use = "pairwise.complete.obs")
corrplot(corr = corr,
title = "")
})
}
shinyApp(ui, server)
I changed your ui and server a bit, but I think that might solve your problem.
I deleted the observeEvent(input$file, ...{}) from the server and added the ui part in the Ui directly.
I also added 3 req() calls in the data reactive, in the second observeEvent(input$select04, ...{}) which I changed to a normal observe and in the renderPlot call.
library(shiny)
library(readr)
library(corrplot)
library(DT)
# File used for the example
data(iris)
write.csv(x = iris, file = "iris.csv", row.names = F)
#UI
ui <- shinyUI(
fluidPage(
navbarPage(
id = "navbar",
tabPanel(
title = "UPLOAD",
br(),
actionButton(inputId = "file", label = "ADD A FILE"),
tabPanel(
value = "B",
title = "Corr",
sidebarLayout(
sidebarPanel(
selectizeInput(width = "300px",
inputId = "select04",
label = "Select features",
choices = NULL,
multiple = TRUE)
),
mainPanel(
plotOutput(
outputId = "corrplot01", height = "650px")
)
)
)
)
)
)
)
#SERVER
server <- function(input, output, session) {
path <- reactiveValues(pth = NULL)
file.choose2 <- function(...) {
pathname <- NULL;
tryCatch({
pathname <- file.choose();
}, error = function(ex) {
})
pathname;
}
observeEvent(input$file,{
path$pth <- file.choose2()
})
observeEvent(input$file, {
newvalue <- "B"
updateNavbarPage(session, "navbar", newvalue)
})
data <- reactive({
req(path$pth)
df <- readr::read_csv(file = path$pth)
return(df)
})
# I suppose there is a problem with this line
observe({
req(names(data()))
col <- names(data())
col.num <- which(sapply(data(), class) == "numeric")
col <- col[col.num]
updateSelectizeInput(session = session, inputId = "select04", choices = col)
})
output$corrplot01 <- renderPlot({
req(input$select04)
df <- data()
df1 <- df[,input$select04]
corr <- cor(x = df1, use = "pairwise.complete.obs")
corrplot(corr = corr,
title = "")
})
}
shinyApp(ui, server)

Print str() of table in shiny dashboard

I am a newbie to shiny dashboard. I want to know how to print str() of the table which i have imported in shiny dashboard. my code is not working. When i print str(), i get the below output,
str()
Please check the code which i have written,
library(shiny)
library(shinydashboard)
library(DT)
ui <- dashboardPage(
dashboardHeader(title = "Analytics Workbench 2.0", titleWidth = 250,
dropdownMenuOutput("msgs")),
dashboardSidebar(
sidebarMenu(
fileInput("Table1", "Train Data"),
fileInput("Table2", "Test Data"),
menuItem("Variable Analysis", icon = icon("edit"),
menuSubItem("Uni-Variate Analysis"),
menuSubItem("Multi-Variate Analysis"))
)
),
dashboardBody(
fluidRow(
column(12, box(title = "Train Data", width = 6, solidHeader = TRUE, status = "warning",
collapsible = TRUE, DT::DTOutput("Train")),
box(title = "Test Data", width = 6, solidHeader = TRUE, status = "warning",
collapsible = TRUE, DT::DTOutput("Test")))),
fluidRow(
column(12, box(title = "Structure", width = 6, solidHeader = TRUE, status = "warning",
collapsible = TRUE, verbatimTextOutput("str1")),
box(title = "Structure", width = 6, solidHeader = TRUE, status = "warning",
collapsible = TRUE, verbatimTextOutput("str2"))))
)
)
server <- function(input, output) {
output$msgs <- renderMenu({
msg <- apply(read.csv("messages.csv"), 1, function(row){
messageItem(from = row[["from"]], message = row[["message"]]) })
dropdownMenu(type = "messages", .list = msg)
})
output$Train <- DT::renderDT({
if (is.null(input$Table1)) return(NULL)
data1 <- read.table(input$Table1$datapath, fill = TRUE, header=T, sep=",")
DT::datatable(data1, options = list(scrollX = TRUE))
})
output$Test <- DT::renderDT({
if (is.null(input$Table2)) return(NULL)
data2 <- read.table(input$Table2$datapath, fill = TRUE, header=T, sep=",")
DT::datatable(data2, options = list(scrollX = TRUE))
})
output$str1 <- renderText({
paste(capture.output(str(input$Table1)), collapse = "\n")
})
output$str2 <- renderText({
paste(capture.output(str(input$Table1)), collapse = "\n")
})
}
I am not able to find out the input to be given for str()
Thanks
Balaji
Switch out your textOutput for verbatimTextOutput. Also, you require a reactive to treat the fileInput... specifically take note that you should trap the case when the input value is NULL.
app.R
library(shiny)
write.csv(mtcars, "mtcars.csv") # file created to test file input
ui <- fluidPage(
mainPanel(
verbatimTextOutput("strfile"),
fileInput("file1", "File")
)
)
server <- function(input, output) {
df <- reactive({
if (is.null(input$file1)) {
return(NULL)
} else {
read.csv(input$file1$datapath, row.names = 1) # note the row.names are dependent on your input requirements
}
})
output$strfile <- renderPrint({str(df())})
}
shinyApp(ui = ui, server = server)
To get this output...

Resources