i'm quite new to shiny, and am trying to make a shiny app which allows the user to download all possible combination of a certain data with a simple download button.
However, it seems that shiny isn't allowing a standard for loop that i've been using outside of shiny
so basically what I'm trying to do with this reproducible data is to allow users to download all 9 possible scatter plots (1,1),(1,2),(1,3) etc
I've tried using lapply, isolate, local and so on, but it simple would either make 3 of the same plots, or not work like the current code
Help would be very, very, very appreciated.
Thank you in advance
this is my current UI
#UI
library(shiny)
library(datasets)
library(ggplot2)
Test1<- c(3,5,7)
Test2<- c(21000, 23400, 26800)
Test3<- c(600, 700, 800)
df <- data.frame(Test1, Test2, Test3)
rownames(df)<-colnames(df)
*ui <- shinyUI(fluidPage(
titlePanel("Column Plot"),
tabsetPanel(
tabPanel("First Type",
pageWithSidebar(
headerPanel('My First Plot'),
sidebarPanel(
selectInput('xcol', 'X Variable', ""),
selectInput('ycol', 'Y Variable', "", selected = ""),
actionButton(inputId = "clicks_3",label = "Real"),
),
mainPanel(
plotOutput('MyPlot')
)
)
)
)
)
)
this is my server
server <- shinyServer(function(input, output, session) {
data <- reactive({
updateSelectInput(session, inputId = 'xcol', label = 'X Variable',
choices = names(df), selected = names(df))
updateSelectInput(session, inputId = 'ycol', label = 'Y Variable',
choices = names(df), selected = names(df)[2])
return(df)
})
output$contents <- renderTable({
data()
})
output$MyPlot <- renderPlot({
x <- data()[, c(input$xcol, input$ycol)]
plot(x)
})
observeEvent(input$clicks_3,{
for (i in 1:3){
assign(paste("Plotinput_",i,sep = ""),({
x <- data()[, c(colnames(data())[i], input$ycol)]
plot(x)
}))
lapply(1:3, function(k){local({
ggsave(plot = eval(parse(text=paste("Plotinput_",k,sep = ""))),filename = paste(k,"barplot.png",collapse = ""))
})
})
}
})
})
If you want to download all plots, I would recommend a markdown report solution. In there, you can use lapply and iterate over all your plots. See https://shiny.rstudio.com/articles/generating-reports.html
In your code, it seems the brackets are not correct, see part below for a solution
observeEvent(input$clicks_3,{
for (i in 1:3){
assign(paste("Plotinput_",i,sep = ""),({
x <- data()[, c(colnames(data())[i], input$ycol)]
plot(x)
}))
}
lapply(1:3, function(k){local({
ggsave(plot = eval(parse(text=paste("Plotinput_",k,sep = ""))),filename = paste(k,"barplot.png",collapse = ""))
})
})
})
Related
I am trying to plot using ggplot in R shiny. I want to upload data and any variable can be used for plotting. I am trying to keep aes() dynamically. I tried a few examples example 1, but dint work for me. Here is my code:
library(shiny)
library(shinydashboard)
library(readxl)
library(DT)
library(dplyr)
library(ggplot2)
# Define UI for application that draws a histogram
ui <- fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput('file1', 'Upload data File',
accept=c('text/csv','.xlsx',
'text/comma-separated-values,text/plain',
'.csv'))),
mainPanel(
DT::dataTableOutput('contents')
)
),
tabPanel("First Type",
pageWithSidebar(
headerPanel('Visualization of Dengue Cases'),
sidebarPanel(
selectInput('xcol', 'X Variable', ""),
selectInput('ycol', 'Y Variable', "", selected = "")
),
mainPanel(
plotOutput('MyPlot')
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output,session) {
data <- reactive({
req(input$file1)
inFile <- input$file1
df <- read_excel(paste(inFile$datapath, sep=""), 1)
updateSelectInput(session, inputId = 'xcol', label = 'X Variable',
choices = names(df), selected = names(df))
updateSelectInput(session, inputId = 'ycol', label = 'Y Variable',
choices = names(df), selected = names(df)[2])
return(df)
})
output$contents <- DT::renderDataTable({
data()
},options = list(pageLength = 10, width="100%", scrollX = TRUE))
output$MyPlot <- renderPlot({
select_quo <- quo(input$MyPlot_select)
data %>%
mutate(user_input = !!select_quo) %>%
ggplot(aes(fill=user_input, y=user_input, x= user_input)) +
geom_bar( stat="identity")
})
}
# Run the application
shinyApp(ui = ui, server = server)
Can use any data set, such as Diamond dataset.
Also kindly help in allowing all types of formats (.csv, .txt,.xls) of data. As of now, only .xls is acceptable.
There are several issues with your code.
You use data instead of data() in the renderPlot
There is no input input$MyPlot_select.
Using quo and !! will not give the desired result. Instead you could simply use the .data pronoun if your column names are strings.
Add req at the beginning of renderPlot.
This said your renderPlot should look like so:
output$MyPlot <- renderPlot({
req(input$xcol, input$ycol)
x <- input$xcol
y <- input$ycol
fill <- input$xcol
ggplot(data(), aes(x = .data[[x]], y = .data[[y]], fill=.data[[fill]])) +
geom_col()
})
For the second part of your question. To make your app work for different types of input files you could get the file extension using e.g. tools::file_ext and use the result in switch statement.
Full reproducible code:
library(shiny)
library(shinydashboard)
library(readxl)
library(DT)
library(dplyr)
library(ggplot2)
ui <- fluidPage(
titlePanel("Uploading Files"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Upload data File",
accept = c(
"text/csv", ".xlsx",
"text/comma-separated-values,text/plain",
".csv"
)
)
),
mainPanel(
DT::dataTableOutput("contents")
)
),
tabPanel(
"First Type",
pageWithSidebar(
headerPanel("Visualization of Dengue Cases"),
sidebarPanel(
selectInput("xcol", "X Variable", ""),
selectInput("ycol", "Y Variable", "", selected = "")
),
mainPanel(
plotOutput("MyPlot")
)
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
data <- reactive({
req(input$file1)
inFile <- input$file1
type <- tools::file_ext(inFile$name)
filename <- inFile$datapath
df <- switch(type,
"xlsx" = read_excel(filename),
"csv" = read_csv(filename),
"tsv" = read_tsv(filename))
updateSelectInput(session,
inputId = "xcol", label = "X Variable",
choices = names(df), selected = names(df)
)
updateSelectInput(session,
inputId = "ycol", label = "Y Variable",
choices = names(df), selected = names(df)[2]
)
return(df)
})
output$contents <- DT::renderDataTable({
data()
}, options = list(pageLength = 10, width = "100%", scrollX = TRUE))
output$MyPlot <- renderPlot({
req(input$xcol, input$ycol)
x <- input$xcol
y <- input$ycol
fill <- input$xcol
ggplot(data(), aes(x = .data[[x]], y = .data[[y]], fill=.data[[fill]])) +
geom_col()
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm not able to modify the script below to make it work with multiple independent variables. It only works when a single independent variable is selected. I've added "multiple = TRUE" in the script to allow the selection of multiple variable at the same time. But that doesn't really affect the plots and stats generated. Any suggestion of how this can be resolved?
Any csv file with numeric and non numeric data would work to test the script. Saving the iris or mtcars r datasets as csv files would work to test the script.
Thank you for your help.
library(shiny)
library(DT)
library(shinyWidgets)
ui <- fluidPage(
titlePanel("Build a Linear Model"),
sidebarPanel(
fileInput(
inputId = "filedata",
label = "Upload data. csv",
multiple = FALSE,
accept = c(".csv"),
buttonLabel = "Choosing ...",
placeholder = "No files selected yet"
),
uiOutput("xvariable"),
uiOutput("yvariable")
), #sidebarpanel
mainPanel( #DTOutput("tb1"),
fluidRow(column(6, verbatimTextOutput('lmSummary')) , column(6, plotOutput('diagnosticPlot')))
)
) #fluidpage
server <- function(input, output) {
data <- reactive({
req(input$filedata)
inData <- input$filedata
if (is.null(inData)){ return(NULL) }
mydata <- read.csv(inData$datapath, header = TRUE, sep=",")
})
output$tb1 <- renderDT(data())
output$xvariable <- renderUI({
req(data())
xa<-colnames(data())
pickerInput(inputId = 'xvar',
label = 'Select x-axis variable',
choices = c(xa[1:length(xa)]), selected=xa[1],
options = list(`style` = "btn-info"))
})
output$yvariable <- renderUI({
req(data())
ya<-colnames(data())
pickerInput(inputId = 'yvar',
label = 'Select y-axis variable',
choices = c(ya[1:length(ya)]), selected=ya[2],
options = list(`style` = "btn-info"),
multiple = TRUE)
})
lmModel <- reactive({
req(data(),input$xvar,input$yvar)
x <- as.numeric(data()[[as.name(input$xvar)]])
y <- as.numeric(data()[[as.name(input$yvar)]])
if (length(x) == length(y)){
model <- lm(x ~ y, data = data(), na.action=na.exclude)
}else model <- NULL
return(model)
})
output$lmSummary <- renderPrint({
req(lmModel())
summary(lmModel())
})
output$diagnosticPlot <- renderPlot({
req(lmModel())
par(mfrow = c(2,2))
plot(lmModel())
})
}
shinyApp(ui = ui, server = server)
You have 2 issues in your code:
the naming convention is wrong; y is usually the dependent variable and x the independent
by extracting the selected columns as vectors out of the data.frame, you loose the nice features of the non-standard evaluation of R, especially for the names of your model. I think this is also the problem that it doesn't work with multiple independent variables
Instead of extracting the data, I use the selected variables to define the formula that can be used in the lm call:
library(shiny)
library(DT)
library(shinyWidgets)
ui <- fluidPage(
titlePanel("Build a Linear Model"),
sidebarPanel(
fileInput(
inputId = "filedata",
label = "Upload data. csv",
multiple = FALSE,
accept = c(".csv"),
buttonLabel = "Choosing ...",
placeholder = "No files selected yet"
),
uiOutput("xvariable"),
uiOutput("yvariable")
), #sidebarpanel
mainPanel( #DTOutput("tb1"),
fluidRow(column(6, verbatimTextOutput('lmSummary')) , column(6, plotOutput('diagnosticPlot')))
)
) #fluidpage
server <- function(input, output) {
data <- reactive({
req(input$filedata)
inData <- input$filedata
if (is.null(inData)){ return(NULL) }
mydata <- read.csv(inData$datapath, header = TRUE, sep=",")
})
output$tb1 <- renderDT(data())
output$xvariable <- renderUI({
req(data())
xa<-colnames(data())
pickerInput(inputId = 'xvar',
label = 'Select x-axis variable',
choices = c(xa[1:length(xa)]), selected=xa[2],
options = list(`style` = "btn-info"),
multiple = TRUE)
})
output$yvariable <- renderUI({
req(data())
ya<-colnames(data())
pickerInput(inputId = 'yvar',
label = 'Select y-axis variable',
choices = c(ya[1:length(ya)]), selected=ya[1],
options = list(`style` = "btn-info"),
multiple = FALSE)
})
lmModel <- reactive({
req(data(),input$xvar,input$yvar)
x <- as.numeric(data()[[as.name(input$xvar)]])
y <- as.numeric(data()[[as.name(input$yvar)]])
current_formula <- paste0(input$yvar, " ~ ", paste0(input$xvar, collapse = " + "))
current_formula <- as.formula(current_formula)
model <- lm(current_formula, data = data(), na.action=na.exclude)
return(model)
})
output$lmSummary <- renderPrint({
req(lmModel())
summary(lmModel())
})
output$diagnosticPlot <- renderPlot({
req(lmModel())
par(mfrow = c(2,2))
plot(lmModel())
})
}
shinyApp(ui = ui, server = server)
I am trying to create a shiny app which includes radioButtons which are reactive to some user input.
I was successful to implement the code from this related question:
Add n reactive radioButtons to shiny app depending on user input
However, in this question it is not described how to access this values.
Here is the example:
server.R
library(shiny)
shinyServer( function(input, output, session) {
output$variables <- renderUI({
numVar <- length(as.integer(input$in0))
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic",x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})
})
})
ui.R
library(shiny)
shinyUI(pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel()
))
What I have tried so far:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
in <- noquote(paste0("dynamic",input$in0[i]))
input$in
}
However, this does not work. Any suggestions?
I'm not sure exactly of your use case but to access the values you could edit your code as below:
numVar <- length(as.integer(input$in0))
for(i in 1:numVar){
value <- paste0("dynamic",input$in0[i])
input[[value]]
}
Basically you need to use input[[value]] as opposed to input$value in this case. It doesn't seem that R allows you to use in as a variable (probably because it's already used in other contexts). You don't need noquote() anymore.
Welcome to stackoverflow!
You were almost there. However, you'll have to make sure, that you are accessing the inputs in a reactive context.
Here is a working example:
library(shiny)
ui <- fluidPage(
pageWithSidebar (
headerPanel("mtcars subset"),
sidebarPanel(
selectInput(inputId = 'in0', label = 'Choose variables',
choices = colnames(mtcars),
multiple = TRUE, selectize = TRUE),
uiOutput("variables")
),
mainPanel(
textOutput("myChoicesDisplay")
)
)
)
server <- function(input, output, session) {
output$variables <- renderUI({
lapply(input$in0, function(x) {
list(radioButtons(paste0("dynamic", x), x,
choices = c("Choice one" = "one",
"Choice two" = "two"), selected = "one"))
})
})
myChoices <- reactive({
dynInputList <- list()
for(dynInputs in paste0("dynamic", input$in0)){
dynInputList[[dynInputs]] <- input[[dynInputs]]
}
return(dynInputList)
})
output$myChoicesDisplay <- renderText({
paste(input$in0, myChoices(), sep = ": ", collapse = ", ")
})
}
shinyApp(ui, server)
I don't know why my ggplot does not appear when I run my app. It appears using plot, it works. But using ggplot, nothing appears. No graph! I tried with print() and without it, no result.
My app I import an csv file and from it I plot a graph.
Could you help me, please?
# Server
server <- function(input, output, session) {
# added "session" because updateSelectInput requires it
data <- reactive({
req(input$file1) # require that the input is available
df <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
updateSelectInput(session, inputId = 'xcol', label = 'X Variable',
choices = names(df), selected = names(df)[sapply(df, is.numeric)])
updateSelectInput(session, inputId = 'ycol', label = 'Y Variable',
choices = names(df), selected = names(df)[sapply(df, is.numeric)])
return(df)
})
output$contents <- renderTable({
data()
})
output$MyPlot <- renderPlot({
x <- data()[, c(input$xcol, input$ycol)]
p <- ggplot(x, aes(input$xcol,input$ycol))
p <- p + geom_line() #+ geom_point()
print(p)
# plot(mydata, type = "l",
# xlab = input$xcol,
# ylab = input$ycol)
})
# Generate a summary table of the data uploaded
output$summary <- renderPrint({
y <- data()
summary(y)
})
}
# Create Shiny app
shinyApp( ui = ui, server = server)
There were a few issues in your code: input$xcol and input$ycol are holding character values, therefore you must use aes_string in the ggplot function. Also, you needed to get your tabsetPanel and sidebarLayout straight (minor issue).
Other than that, in your data reactive, you use inputs for sep and quote which are not found in your UI, causing an error. If I comment them out, everything is working as expected. For testing I used write.csv(diamonds, file = "diamonds.csv"):
library(shiny)
library(ggplot2)
shinyApp(
ui = fluidPage(
tabsetPanel(
tabPanel(
"Upload File",
titlePanel("Uploading Files"),
fileInput(
inputId = "file1",
label = "Choose CSV File",
multiple = FALSE,
accept = c("text/csv", "text/comma-separated-values, text/plain", ".csv")
)),
tabPanel(
"Plot",
pageWithSidebar(
headerPanel("Plot your data"),
sidebarPanel(
selectInput("xcol", "X Variable", ""),
selectInput("ycol", "Y Variable", "", selected = "")
),
mainPanel(plotOutput("MyPlot"))
)
)))
,
server <- function(input, output, session) {
# added "session" because updateSelectInput requires it
data <- reactive({
req(input$file1) # require that the input is available
df <- read.csv(input$file1$datapath)#,
# no such inputs in your UI
# header = input$header,
# sep = input$sep,
# quote = input$quote
# )
updateSelectInput(session,
inputId = "xcol", label = "X Variable",
choices = names(df), selected = names(df)[sapply(df, is.numeric)]
)
updateSelectInput(session,
inputId = "ycol", label = "Y Variable",
choices = names(df), selected = names(df)[sapply(df, is.numeric)]
)
return(df)
})
output$contents <- renderTable({
data()
})
output$MyPlot <- renderPlot({
x <- data()[, c(input$xcol, input$ycol)]
p <- ggplot(x, aes_string(input$xcol, input$ycol))
p <- p + geom_line() #+ geom_point()
print(p)
# plot(mydata, type = "l",
# xlab = input$xcol,
# ylab = input$ycol)
})
# Generate a summary table of the data uploaded
output$summary <- renderPrint({
y <- data()
summary(y)
})
}
)
I am tying to create an R shiny app and I would like to have two selectInput i.e. data set name and column name. Right now, I am able to get data set names in the first Input but I am not able to create dependent column selectIput (whose list will depend upon data set selected). Please guide.
require(shiny)
require(MASS)
a <- data(package = "MASS")[3]
b <- a$results[,3]
ui <- fluidPage(
sidebarPanel(width = 2,
selectInput(inputId = "dsname",label = "Select Dataset:",choices = c(b)),
colnames <- names("dsname"),
selectInput(inputId = "columns", label = "Choose columns",
choices = c(colnames))
)
)
server <- function(input,output) {}
shinyApp(ui <- ui, server <- server)
In order to have "responsive" elements in Shiny, you need to wrap your expressions for computing the responsive elements in reactive({...}).
You could use renderUI in your server() and uiOutput in your ui() with something like this. Here is an example I had built for using some of R's data sets (iris, mtcars, and diamonds):
library(shinythemes)
library(shiny)
library(ggplot2)
ui <- fluidPage(theme = shinytheme("superhero"),
titlePanel("Welcome to Responisve Shiny"),
sidebarLayout(
sidebarPanel(
selectInput("data", "Dataset:",
choices = c("mtcars", "iris", "diamonds")
),
uiOutput("x_axis"),
uiOutput("y_axis"),
uiOutput("color")
),
mainPanel(
plotOutput("distPlot")
)
)
)
server <- function(input, output) {
output$x_axis <- renderUI({
col_opts <- get(input$data)
selectInput("x_axis2", "X-Axis:",
choices = names(col_opts))
})
output$y_axis <- renderUI({
cols2 <- reactive({
col_opts2 <- get(input$data)
names(col_opts2)[!grepl(input$x_axis2, names(col_opts2))]
})
selectInput("y_axis2", "Y-Axis:",
choices = cols2(),
selected = "hp")
})
output$color <- renderUI({
col_opts <- get(input$data)
selectInput("color", "Color:",
choices = names(col_opts),
selected = "cyl")
})
output$distPlot <- renderPlot({
if(input$data == "mtcars"){
p <- ggplot(mtcars, aes_string(input$x_axis2, input$y_axis2, color = input$color)) +
geom_point()
}
if(input$data == "iris"){
p <- ggplot(iris, aes_string(input$x_axis2, input$y_axis2, color = input$color)) +
geom_point()
}
if(input$data == "diamonds"){
p <- ggplot(diamonds, aes_string(input$x_axis2, input$y_axis2, color = input$color)) +
geom_point()
}
print(p)
})
}
shinyApp(ui = ui, server = server)