How to convert a Shiny app consisting of multiple files into an easily shareable and reproducible Shiny example?
Example data
Of course, all guidelines regarding sample data mentioned in the answer on the question “how to make a great R reproducible example” also hold when creating questions related to Shiny
. To summarize: Make sure no additional files are needed to run your code. Use sample datasets like mtcars
, or create some sample data with data.frame()
. If your data is very complex and that complexity is really required to illustrate the issue, you could also use dput()
. Avoid using functions like read.csv()
, unless of course you have questions related to functions like fileInput
.
Example code
Always reduce your code to the bare minimum to reproduce your error or unexpected behavior. This includes removing calls to additional .CSS
files and .js
files and removing unnecessary functions in the ui
and the server
.
Shiny apps often consist of two or three files (ui.R
, server.R
and possibly global.R
), for example this demo application. However, it is preferable to post your code as a single script, so it can easily be run by others without having to manually create those files. This can easily be done by:
- wrapping your ui with
ui <- fluidPage(…)
, - the server with
server <- function(input,output, session) {…}
, - and subsequently calling
shinyApp(ui, server)
.
So a simple skeleton to start with could look as follows:
library(shiny)
ui <- fluidPage(
)
server <- function(input,output,session) {
}
shinyApp(ui, server)
Working Example
So, taking all the above into account, a good Minimal, Complete, and Verifiable example for a Shiny application could look as follows:
library(shiny)
df <- data.frame(id = letters[1:10], value = seq(1,10))
ui <- fluidPage(
sliderInput('nrow', 'Number of rows', min = 1, max = 10, value = 5),
dataTableOutput('my_table')
)
server <- function(input, output, session) {
output$my_table <- renderDataTable({
df[1:input$nrow,]
})
}
shinyApp(ui, server)
Adding CSS
There are multiple ways to add custom CSS to a Shiny application, as explained here. The preferred way to add CSS to a Shiny application in a reproducible example is to add the CSS in the code, rather than in a separate file. This can be done by adding a line in the ui
of an application, for example as follows:
tags$head(tags$style(HTML('body {background-color: lightblue;}'))),
How to integrate code into a shiny app and upload files?
Here is a minimal example showing uploading files, processing them, and downloading them.
For simplicity I've used 3 inputs and a single output.
If you want to notify a user that something has happened, you can use showNotification()
library(shiny)
ui <- fluidPage(
#File Upload Boxes
fileInput("myfileinput_1", label = "Upload File 1", accept = ".csv"),
fileInput("myfileinput_2", label = "Upload File 2", accept = ".csv"),
fileInput("myfileinput_3", label = "Upload File 3", accept = ".csv"),
#Button
actionButton("mybutton", label = "Process Uploaded Files"),
#Table Showing Processed Data
tableOutput("mytable"),
#Download Buttons
downloadButton("myfiledownload", label = "Download Processed File")
)
server <- function(input, output, session) {
#A reactive dataframe to store our outputfile
reactives <- reactiveValues(
df_output = NULL
)
#Runs when button is pressed
observeEvent(input$mybutton, {
#Check that all 3 files are selected before loading
if(!is.null(input$myfileinput_1) & !is.null(input$myfileinput_2) & !is.null(input$myfileinput_3)) {
#Load input files
df_input_1 <- read.csv(input$myfileinput_1$datapath)
df_input_2 <- read.csv(input$myfileinput_2$datapath)
df_input_3 <- read.csv(input$myfileinput_3$datapath)
#Use input to create an output (we're just using a simple example)
reactives$df_output <- data.frame(
input = c("Input 1", "Input 2", "Input 3"),
rows = c(nrow(df_input_1), nrow(df_input_2), nrow(df_input_3))
)
showNotification("Files Successfully Processed", type = "message")
} else {
showNotification("Ensure all three files are selected before loading", type = "error")
}
})
#Table Output
output$mytable <- renderTable({
reactives$df_output
})
#Download handler
output$myfiledownload <- downloadHandler(
filename = "mydata.csv",
content = function(file) {write.csv(reactives$df_output, file, row.names = FALSE)}
)
}
shinyApp(ui, server)
How can I properly override default styles in a shiny application?
Shiny allows you to disable the use of bootstrap giving you the freedom to start your styling from scratch:
library(shiny)
ui <- fluidPage(
tags$head(
# Note the wrapping of the string in HTML()
tags$style(HTML("
body {
background-color: black;
color: white;
}"))
),
tagList(
suppressDependencies("bootstrap"),
tags$p("Hello, world!")
),
textInput("text", "text"),
numericInput("number", "number", 123)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
Can R Shiny be used to import file, run R script, and export file?
This is my first answer but i worked a lot with Shiny.
Of course you can do what you ask for. You just need to merge the fileInput function and the downloadButton / downloadLink.
https://shiny.rstudio.com/reference/shiny/1.0.4/downloadButton.html
https://shiny.rstudio.com/gallery/file-upload.html
Here i wrote a quick example, you just need to copy and save with the name app.R :
library(shiny)
# Define UI for data upload app ----
ui <- fluidPage(
# App title ----
titlePanel("Welcome to Ethar data transformation app"),
# App subtitle
h4(HTML("Upload your file and click the Download button")),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel ----
sidebarPanel(
# Input: Select a file ----
fileInput("fileUploaded", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
# Output: Download a file ----
downloadButton('downloadFile', 'Process the file & Download', class= "action"),
# CSS style for the download button ----
tags$style(type='text/css', "#downloadFile { width:100%; margin-top: 35px;}")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
textOutput("done")
)
)
)
# Define server logic to read selected file ----
server <- function(input, output) {
# Download handler in Server
output$downloadFile <- downloadHandler(
filename = function() {
paste('dataProcessed-', Sys.Date(), '.csv', sep='')
},
content = function(con) {
originalData <- input$fileUploaded
##############################
# Transformations in originalData object
##############################
dataProcesed <- originalData
write.csv(dataProcesed, con)
output$done <- renderText({
ifelse(!is.null(dataProcesed),"Transformation done! :D","Error during the process :(")
})
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
Hope it helps! :)
Related Topics
Counting Unique Values Across Variables (Columns) in R
How to Generate a Histogram for Each Column of My Table
Coerce Multiple Columns to Factors At Once
Change Rows into Columns in R With Values Yes/No (1/0)
How to Generate the First N Terms in the Series:
Column Name Changes in R for Loop for Defined Data Frame
Installing Rgl on Ubuntu and Mac: X11 Not Found
How to Reshape Data from Long to Wide Format
How to Sum a Variable by Group
Dynamically Select Data Frame Columns Using $ and a Character Value
How to Convert a Factor to Integer\Numeric Without Loss of Information
Transpose/Reshape Dataframe Without "Timevar" from Long to Wide Format
How to Deal With "Package 'Xxx' Is Not Available (For R Version X.Y.Z)" Warning
Split Data Frame String Column into Multiple Columns
Select the Row With the Maximum Value in Each Group
Combine (Rbind) Data Frames and Create Column With Name of Original Data Frames