I'm trying to get a Rshiny code to display two panels on the left hand side (one for file input and the other to action plot) and a plot on the right hand side, but I got the following error:
Error in match.arg(position) : 'arg' must be NULL or a character vector
Here is the code:
library(shiny)
library(pheatmap)
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel("Sidebar panel",
# Input: Selector for choosing dataset ----
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
# tags$hr(),
sidebarPanel('get heatmap',
actionButton('getHmap', 'get heatmap')
),
# Main panel for displaying outputs ----
mainPanel("Plot",
#column(6,
plotOutput("themap"),
tableOutput("table.output"))
#)
)
)
server = function(input, output, session) {
a <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
tbl <- read.csv(inFile$datapath, header=input$header) #, sep=input$sep, dec = input$dec)
return(tbl)
})
output$table.output <- renderTable({
a()
})
plotdata <- eventReactive(input$getHmap, {
a <- as.matrix(a()[-1])
row.names(a) <- a()$ID
a[is.na(a)] <- 0
a
})
output$themap = renderPlot({
pheatmap(plotdata())
})
}
shinyApp(ui, server)
I'm new to Rshiny. Can someone help me find the cause of this problem please?
Related
I am new to R shiny and I hope someone can please guide me in the right direction.
I want the user to be able to select one or multiple datasets to download.
Code works when I put the multiple=F in selectInput but when I change it to TRUE, I get the error below:
"Warning: Error in switch: EXPR must be a length 1 vector"
Any help will be greatly appreciated as I am stuck on this for days.
Thank you
library(shiny)
library(openxlsx)
# Define UI for data download app ----
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple=T),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
tableOutput("table")
)
)
)
# Define server logic to display and download selected file ----
server <- function(input, output) {
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})
# Table of selected dataset ----
output$table <- renderTable({
datasetInput()
})
# Downloadable xlsx of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
"selected.xlsx"
},
content = function(filename) {
write.xlsx(datasetInput(), file = filename, rowNames = FALSE)
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
In order to display several datasets, you can create a module (it is like creating a smaller shiny app inside your shiny app that you can call with parameters, just like a function). Here I created a module to display a table, with a dataframe as parameter.
For the download, I followed the link I gave you previously.
library(shiny)
#Using module
mod_export_table_ui <- function(id){
ns <- NS(id)
tagList(
tableOutput(ns("table_export"))
)
}
mod_export_table_server <- function(input, output, session, df_export){
ns <- session$ns
output$table_export <- renderTable({
df_export
})
}
# Define UI for data download app ----
ui <- fluidPage(
# App title ----
titlePanel("Downloading Data"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a dataset:",
choices = c("rock", "pressure", "cars"), multiple=T),
# Button
downloadButton("downloadData", "Download")
),
# Main panel for displaying outputs ----
mainPanel(
uiOutput("tables")
)
)
)
# Define server logic to display and download selected file ----
server <- function(input, output, session) {
rv <- reactiveValues()
#List of datasets
observeEvent(input$dataset, {
req(input$dataset)
rv$lst_datasets <- lapply(
1:length(input$dataset),
function(i) {
head(eval(parse(text =input$dataset[i])))
}
)
})
# Module UIs
output$tables <- renderUI({
req(rv$lst_datasets)
lapply(
1:length(rv$lst_datasets),
function(i) {
mod_export_table_ui(id = paste0("table", i))
}
)
})
# Module Servers
observeEvent(rv$lst_datasets, {
req(rv$lst_datasets)
lapply(
1:length(rv$lst_datasets),
function(i) {
callModule(
module = mod_export_table_server,
session = session,
id = paste0("table", i),
df_export = rv$lst_datasets[[i]]
)
}
)
})
output$downloadData <-downloadHandler(
filename = "Downloads.zip",
content = function(file){
withProgress(message = "Writing Files to Disk. Please wait...", {
temp <- setwd(tempdir())
on.exit(setwd(temp))
files <- c()
for(i in 1:length(rv$lst_datasets)){
writexl::write_xlsx(rv$lst_datasets[[i]],
path = paste0("dataset",i, ".xlsx")
)
files <- c(files, paste0("dataset",i, ".xlsx"))
}
zip(zipfile = file, files = files)
})
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
I will like to use the code below to output a dashboard with 2 panels on the left (Top panel: input file; Bottom panel: action plot) and plot (main page) on the right. Currently, the code outputs the two panels at the top part of dashboard and plot at the bottom, and this is not what I want. I'm new to Rshiny and need help.
Code:
library(shiny)
library(pheatmap)
# Define UI for dataset viewer app ----
ui <- fluidPage(
# App title ----
titlePanel("plot"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel("Sidebar panel",
# Input: Selector for choosing dataset ----
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
# tags$hr(),
sidebarPanel('get heatmap',
actionButton('getHmap', 'get heatmap'))
),
# Main panel for displaying outputs ----
mainPanel("Plot",
#column(6,
plotOutput("themap"),
tableOutput("table.output"))
#)
)
server = function(input, output, session) {
a <- reactive({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
tbl <- read.csv(inFile$datapath, header=input$header) #, sep=input$sep, dec = input$dec)
return(tbl)
})
output$table.output <- renderTable({
a()
})
plotdata <- eventReactive(input$getHmap, {
a <- as.matrix(a()[-1])
row.names(a) <- a()$ID
a[is.na(a)] <- 0
a
})
output$themap = renderPlot({
pheatmap(plotdata())
})
}
shinyApp(ui, server)
Does anyone know how to use Rshiny fluidpage and columns well and can help?
I'm not entirely sure what you want, but you do have two sidebarPanels in your UI, which isn't helping. How about:
ui <- fluidPage(
titlePanel("plot"),
sidebarLayout(
sidebarPanel("Sidebar panel",
# Input: Selector for choosing dataset ----
fileInput("file1", "Choose CSV File",
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE),
actionButton('getHmap', 'get heatmap')
),
mainPanel("Plot",
#column(6,
plotOutput("themap"),
tableOutput("table.output")
)
)
)
as your UI?
** Edit **
If this isn't what you want, as per your comment below, then please provide more information. Here's a screenshot of what this layout gives me:
which has your plot to the right at the top of the main panel and two controls in the panel to the left: the input file at the top and an action button below. That seems to match your spec in the question. (Although I wasn't sure what you meant by "action plot", so I assumed you meant "action button" as that's what your sample code had.) Note that the plot doesn't actually appear because I haven't installed the pheatmap package and you haven't provided any test data.
I have a simple shiny app below. In this app I want the user to be able to upload his own csv and then automatically this will be added as a choice in the checkbox group below the other dataset "D.B" (which I create in my original app).
#ui.r
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
uiOutput("checkbox"),
textInput("filename","Set Filename")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output) {
output$contents <- renderTable({
req(input$file1)
df <- read.csv(input$file1$datapath)
})
D.B <- reactive({
#some code that creates the dataset D.B.
})
output$checkbox<-renderUI({
checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = c("D.B")
)
})
}
You could use a reactive value to store choices then add a choice everytime a file is uploaded. Use an observer to watch for file uploads (I also used the library rlist which gives me the append method).
library(rlist)
#ui.r
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
uiOutput("checkbox"),
textInput("filename","Set Filename")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
#fileOptions = list("D.B.")
server <- function(input, output, session) {
output$contents <- renderTable({
req(input$file1)
df <- read.csv(input$file1$datapath)
head(df)
})
fileOptions <- reactiveValues(currentOptions=c("D.B."))
observeEvent(input$file1, {
fileOptions$currentOptions = list.append(fileOptions$currentOptions, input$file1$datapath)
})
D.B <- reactive({
#some code that creates the dataset D.B.
})
output$checkbox<-renderUI({
checkboxGroupInput("datasetSelector","Specify the datasets to compare:", choices = fileOptions$currentOptions
)
})
}
I have a simple shiny app below. In this app I want the user to be able to upload his own csv and then automatically this will be added as a choice in the checkbox group below the other dataset "D.B" (which I create in my original app). Then when the user chooses a file it will be displayed as a table.
Here I have managed to rename the uploaded file. However I can not then connect the renamed table with renderTable() while keeping the "changing name" ability.
# Define UI for data upload app ----
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
checkboxGroupInput("datasetSelector","Data Files", choices=c("D.B")),
textInput("filename","Set Filename",value = "Set Name")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output, session) {
observeEvent(input$filename, {
req(input$file1)
Name<-input$filename
updateCheckboxGroupInput(session,"datasetSelector", choices=c("D.B",Name))
})
observeEvent(input$file1, {
Data<-input$file1$datapath
Name<-input$filename
New <- read.csv(Data)
updateCheckboxGroupInput(session,"datasetSelector",
choices=c("D.B",input$file1$name))
})
D.B <- reactive({
if("D.B"%in% input$datasetSelector){
x <- read.csv("something.csv", stringsAsFactors = F)
}
})
output$contents <- renderTable({
New
})
}
Here is one solution.
This solution uses the ability of shiny inputs to take named lists. In a named list the label is the display name and the value is what is returned. E.g. c("a" = 1, "b" = 2) will display the labels a and b in the UI, but will return values of 1 and 2 in the server.
Because you want one of your labels to come from an input, it is necessary to build the ordered list in two parts. First, the values and then the labels. E.g. mylist = c(1,2) sets up the values then names(mylist) = c("a","b") assigns the labels.
Here is the code I had working:
library(shiny)
# Define UI for data upload app ----
ui <- fluidPage(
# App title ----
titlePanel("Uploading Files"),
# Sidebar layout with input and output definitions ----
sidebarLayout(
# Sidebar panel for inputs ----
sidebarPanel(
# Input: Select a file ----
fileInput("file1", "Choose CSV File",
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
checkboxGroupInput("datasetSelector","Data Files", choices=c("D.B" = "original")),
textInput("filename","Set Filename",value = "Set Name")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
)
#server.r
server <- function(input, output, session) {
observeEvent(input$filename, {
req(input$file1)
Name<-input$filename
# make list
choices = c("original", "loaded")
# assign labels to list
names(choices) = c("D.B", Name)
updateCheckboxGroupInput(session,"datasetSelector", choices=choices)
})
observeEvent(input$file1, {
Data<-input$file1$datapath
Name<-input$filename
New <- read.csv(Data)
# make list
choices = c("original", "loaded")
# assign labels to list
names(choices) = c("D.B", Name)
updateCheckboxGroupInput(session,"datasetSelector", choices=choices)
})
D.B <- reactive({
if("D.B"%in% input$datasetSelector){
x <- read.csv("something.csv", stringsAsFactors = F)
}
})
output_table = reactive({
if("original" %in% input$datasetSelector)
return(D.B())
if("loaded" %in% input$datasetSelector)
return(read.csv(input$file1$datapath))
})
output$contents <- renderTable({
output_table()
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
I want to display a large grid table in Shiny but I can't find a way to do it, as Shiny seems to always truncate my table. The reason why I use a grid table is the fact that it provides some features I need to implement into my table. I managed to display the right-left view but top-bottom view is always truncated. Here is my code :
ui:
library(shiny)
library(gridExtra)
library(grid)
library(gtable)
shinyUI(fluidPage(
mainPanel(
div(class="double-scroll",style='overflow-x:scroll;overflow-y:scroll;
height:1600px; width:1600px;',plotOutput("out"))
)
))
server:
shinyServer(function(input, output,session) {
mat <- matrix(8,nrow=50,ncol=50)
example <- tableGrob(mat,rows=NULL,cols=NULL)
output$out <- renderPlot({grid.draw(example)})
})
In this example, the 50 columns of "8" are shown but only 20 rows are displayed.
Try a code like that:
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose CSV File",
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")
),
tags$hr(),
checkboxInput("header", "Header", TRUE)
),
mainPanel(
tableOutput("contents")
)
)
)
server <- function(input, output) {
output$contents <- renderTable({
inFile <- input$file1
if (is.null(inFile))
return(NULL)
df <- read.csv(inFile$datapath, header = input$header)
print(df[,c(1:16)]) # display only the first 16th columns of your dataset
})
}
shinyApp(ui, server)