Context: I'm trying to make a R shiny server which takes file uploads and displays it in a table in the UI. The file can either be in csv, txt or tsv, meaning read.csv() is not appropriate. Also the table output can change at anytime depending on the user's input of the radiobuttons to determine the delimiter.
Problem: I can't seem to make the table only display the top x number of rows from the file. Does anyone know any possible solutions?
Attempted solutions:
I've tried using renderDataTable function, however it had an error saying that data() is needs to be a matrix or dataFrame. It doesn't make sense since read.table() function would return a dataframe(https://www.rdocumentation.org/packages/utils/versions/3.6.2/topics/read.table). And data <-reactive would mean data is a dataFrame.
Server
server <- function(input, output, session) {
output$distPlot <- renderPlot({
hist(rnorm(input$obs), col = 'darkgray', border = 'white')
})
observe({
# DEFile from fileInput() function
ServerDEFile <- req(input$DEFile)
# extensions tool for format validation
extDEFile <- tools::file_ext(ServerDEFile$datapath)
if(is.null(input$DEFile)){return()
}else{
if (extDEFile == "txt") {
label = paste("Delimiters for", extDEFile, "file")
choice <-c(Comma=",", Semicolon=";", Tab="\t", Space=" ")
}else if (extDEFile == "tsv") {
label = paste("Delimiter: Tab")
choice <- (Tab="\t")
}else {
label = paste("Delimiter: Comma")
choice <- (Comma=",")
}
updateRadioButtons(session, "sepButton", label = label, choices = choice)
}
})
# reactive converts the upload file into a reactive expression known as data
data <- reactive({
# DEFile from fileInput() function
ServerDEFile <- input$DEFile
# extensions tool for format validation
extDEFile <- tools::file_ext(ServerDEFile$datapath)
# file format checking
req(ServerDEFile)
# validate(need(extDEFile == c("csv", "tsv", "txt"), "Please upload a csv, tsv or txt file."))
# convert data into file format
if(is.null(extDEFile)){return()}
read.table(file=ServerDEFile$datapath, sep=input$sepButton)
})
# creates reactive table called DEFileContent
output$DEFileContent <- renderTable({
if(is.null(data())){return ()}
data()
})
# handles rendering of reactive object on tb on ui
output$UIDEContent <- renderUI({
tableOutput("DEFileContent")
})
}
UI
library(shinyWidgets)
library(DT)
library(shiny)
ui <- fluidPage(
titlePanel(title=div(img(src="ODClogo.png", height = 50), "OutDeCo")),
#navbarPage is top menu bar
navbarPage("",
#tabPanel is each tab in the navbarPage
# Assess DE tab
tabPanel(
title="Assess DE",
dropdown(
# title of sidepanel
tags$h3("Options"),
# inputs in the sidepanel
fileInput("DEFile", "Choose DE File",
accept = c(
".csv",
".tsv",
".txt"
)
),
# button for selecting delimiter, default is nothing until file is selected and handled in server side
radioButtons(inputId = 'sepButton', label = 'Delimiter Selector', choices = c(Default=''), selected = ''),
# side panel characteristics
style = "gradient", icon = icon("cog"),
status = "primary", width = "300px",
animate = animateOptions(
enter = animations$fading_entrances$fadeInLeftBig,
exit = animations$fading_exits$fadeOutLeftBig
)
),
navlistPanel(
tabPanel(
title="Cluster Genes",
"Cluster genes Page",
# Navigation Bar for types of plots inside cluster
tabsetPanel(
tabPanel(
title="View file",
mainPanel(
uiOutput("UIDEContent")
)
),
tabPanel(
title="Plot 2"
),
tabPanel(
title="Plot 3"
)
),
),
),
)
),
)
Related
I have a shiny app where the user uploads a csv file. Then, using the column names from the csv file, I create sortable bucket list. I would like drag the column name from the first rank list and have it cloned (i.e. not depleted). I tried to use the options parameter in add_rank_list() setting pull='clone', but that did not work. Any idea on how to do this? Below is my code, and some fake data can be accessed here.
library(shiny)
library(shinyjs)
library(sortable)
ui <- fluidPage(
titlePanel("App"),
sidebarLayout(
sidebarPanel(
useShinyjs(),
fileInput(inputId = "file1", label = "Select a .csv file",
accept = c("text/csv", "text/comma-separated-values,text/plain",".csv")
),
uiOutput("show_button")
),
mainPanel(
DT::dataTableOutput("table")
)
),
fluidRow(uiOutput("buckets"))
)
server <- function(input, output) {
# input csv file
input_file <- reactive({
if (is.null(input$file1)) {
return("")
}
# actually read the file
read.csv(file = input$file1$datapath)
})
# button to hide/show table
## only show when table is loaded
output$show_button = renderUI({
req(input$file1)
actionButton(inputId = "button", label = "show / hide table")
})
## observe the button being pressed
observeEvent(input$button, {
shinyjs::toggle("table")
})
# output table
output$table <- DT::renderDataTable({
# render only if there is data available
req(input_file())
# reactives are only callable inside an reactive context like render
data <- input_file()
data
})
# Drag and Drop Col names
output$buckets = renderUI(
{
# create list of colnames
req(input$file1)
data = input_file()
cols = colnames(data)
# create bucket list
bucket_list(
header = "Drag the items in any desired bucket",
group_name = "bucket_list_group",
orientation = "horizontal",
add_rank_list(
text = "Drag from here",
labels = as.list(cols),
input_id = "rank_list_1",
css_id = "list1",
options = sortable_options(
group = list(
pull = "clone",
name = "list_group1",
put = FALSE))
),
add_rank_list(
text = "to here",
labels = NULL,
input_id = "rank_list_2",
css_id = "list2",
options = sortable_options(group = list(name = "list_group1")))
)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Here is a video which explains what I want.
I want to upload a file and then for each column, a checkbox should appear.
If the checkbox is checked, then a dropdown list and two textinputs should be shown for each column.
If it's not checked, then the checkbox and two textinputs should disappear.
This image has only two text inputs and a dropdown for the first column but it should have two textinput and dropdown for each checkbox.
Check out the analysis tab after uploading a data file
UI code:
shinyUI(
navbarPage(title="Analysis",
tabPanel(title="Input",
sidebarLayout(
sidebarPanel(
fileInput("file","Upload the file"),
checkboxInput('file_has_headers',"Take Column Names from the first row of the file",value= TRUE),
checkboxInput('show_head_only',"Display only first 6 rows. Uncheck this to see entire file",value= TRUE),
radioButtons(inputId = 'sep', label = 'Separator', choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ','),
textAreaInput("domains", 'Enter the comma separated list of dimensions, for example: verbal ability, numerical ability' ),
width = 4
),
mainPanel(
wellPanel(
DT::dataTableOutput("uploaded_table"
),# Displays the uploaded table by using js dataTable from DT package
),
width = 8
),
position = 'left'
)
), #End of Input Tab panel
tabPanel(title="Verification",
fluidRow(
column(2,
"V",
uiOutput('choose_columns')
),
column(2,
"Key",
textInput('anser_key',"",placeholder = 'e.g. A')
),
column(4,
"Dimension",
uiOutput("domain_dropdown",inline = FALSE)
),
column(3,
"Valid Options",
textInput('valid_options',"",placeholder = 'e.g. A,B,C,D')
),
) # End Fluid row
), #End of Verification Tab Panel
navbarMenu(title="Analayis",
tabPanel(title="Item Analysis", "content"
), #End of Item Analysis Tab Panel
tabPanel(title="Test Analysis", "content"
) #End of Test Analysis Tab Panel
) #End of navbarMenu
) #End of navbarPage
) #end of shinyUI
Server code:
library(shiny)
library(DT)
options(shiny.maxRequestSize=300*1024^2)
shinyServer(function(input, output) {
#1: Get the uploaded file in the data variable
data <- reactive({
uploaded <- input$file
#if(is.null(file1)){return("No file is selected or selected file is not in the right format. Please check the documentation and upload correct file.")}
req(uploaded) #req retruns a silence rather than error and is better than using if()
if(input$show_head_only){
head(read.csv(file=uploaded$datapath, sep=input$sep,header = input$file_has_headers)) #head() returns only first 6 rows
} else {
read.csv(file=uploaded$datapath, sep=input$sep,header = input$file_has_headers)
}
})
#2:set the elemet for domain dropdown list.
output$domain_dropdown <- renderUI({
items <- strsplit(input$domains,',')[[1]] #It creates a list and [[1]] retuns the list as c('','') which is needed for select input
selectInput(inputId = "domains", label = "", choices = items)
})
#3: set element to show the uploaded csv file as a table
output$uploaded_table<- DT::renderDataTable(
data(), # If a variable contains the output of reactive() function, it must be used as a function.
server=TRUE, #Important to keep this as true so that large datasets do not crash the browser
options = list(
scrollX = TRUE
),
) # End of uploaded table output setting
#4: Set dynamic checkboxes based on the number of columns in the data
output$choose_columns <- renderUI({
req(data())
colnames <- names(data())
checkboxGroupInput("columns", "Choose columns",
choices = colnames,
# selected = colnames
)
})
})
Perhaps you are looking for this.
ui <- shinyUI(
navbarPage(title="Analysis",
tabPanel(title="Input",
sidebarLayout(
sidebarPanel(
fileInput("file","Upload the file"),
checkboxInput('file_has_headers',"Take Column Names from the first row of the file",value= TRUE),
checkboxInput('show_head_only',"Display only first 6 rows. Uncheck this to see entire file",value= TRUE),
radioButtons(inputId = 'sep', label = 'Separator', choices = c(Comma=',',Semicolon=';',Tab='\t', Space=''), selected = ','),
textAreaInput("domains", 'Enter the comma seperated list of dimensions, for example: verbal ability, numerical ability' ),
width = 4
),
mainPanel(
wellPanel(
DT::dataTableOutput("uploaded_table"
),# Displays the uploaded table by using js dataTable from DT package
),
width = 8
),
position = 'left'
)
), #End of Input Tab panel
tabPanel(title="Verification",
fillRow(flex = c(1,4),
fillCol(uiOutput('choose_columns')),
fillCol(fluidRow(column(8,uiOutput('kdv'))))
) ## end of fillRow
), #End of Verification Tab Panel
navbarMenu(title="Analayis",
tabPanel(title="Item Analysis", "content"
), #End of Item Analysis Tab Panel
tabPanel(title="Test Analysis", "content"
) #End of Test Analysis Tab Panel
) #End of navbarMenu
) #End of navbarPage
) #end of shinyUI
library(shiny)
library(DT)
options(shiny.maxRequestSize=300*1024^2)
server <- shinyServer(function(input, output) {
#1: Get the uploaded file in the data variable
data <- reactive({
uploaded <- input$file
#if(is.null(file1)){return("No file is selected or selected file is not in the right format. Please check the documentation and upload correct file.")}
req(uploaded) #req retruns a silence rather than error and is better than using if()
if(input$show_head_only){
head(read.csv(file=uploaded$datapath, sep=input$sep,header = input$file_has_headers)) #head() returns only first 6 rows
} else {
read.csv(file=uploaded$datapath, sep=input$sep,header = input$file_has_headers)
}
})
#2:set the element for domain dropdown list.
output$domain_dropdown <- renderUI({
req(input$columns)
items <- strsplit(input$columns,',') # [[1]] #It creates a list and [[1]] returns the list as c('','') which is needed for select input
selectInput(inputId = "domains", label = "", choices = items)
})
#3: set element to show the uploaded csv file as a table
output$uploaded_table<- DT::renderDataTable(
data(), # If a variable contains the output of reactive() function, it must be used as a function.
server=TRUE, #Important to keep this as true so that large datasets do not crash the browser
options = list(
scrollX = TRUE
),
) # End of uploaded table output setting
#4: Set dynamic checkboxes based on the number of columns in the data
output$choose_columns <- renderUI({
req(data())
colnames <- names(data())
checkboxGroupInput("columns", "Choose columns",
choices = colnames,
# selected = colnames
)
})
output$kdv <- renderUI({
n <- length(names(data()))
colnames <- names(data())
if (is.null(input$columns)){return(NULL)
}else{
tagList(
lapply(1:n, function(i){
lapply(input$columns , function(par){
if (colnames[i]==par){
div(
div(style="display: inline-block; vertical-align:top; width: 145px ;",textInput(paste0('answer_key',i),"",placeholder = 'e.g. A')),
div(style="display: inline-block; vertical-align:top; width: 155px ;",selectInput(paste0('sel_var',i), "", choices=data()[[par]])),
div(style="display: inline-block; vertical-align:top; width: 145px ;",textInput(paste0('valid_options',i),"",placeholder = 'e.g. A,B,C,D'))
)
}
})
})
)
}
})
})
shinyApp(ui, server)
I'm creating a simple Shiny UI that allow users to either input text or upload file to create a word cloud, the sidebar shows normal, but main panel continues to show
Error in [.data.frame: undefined columns selected'.
Avoid initial warning with default value set in textAreaInput
Key code as below:
ui <- fluidPage(
h1("Word Cloud"),
sidebarLayout(
sidebarPanel(
# Add radio buttons input
radioButtons(
inputId = "source",
label = "Word source",
choices = c(
"Use your own words" = "own",
"Upload a file" = "file"
)
),
conditionalPanel(
condition = "input.source == 'own'",
textAreaInput("text", "Enter text",value="Paste here",rows = 7)
),
conditionalPanel(
condition = "input.source == 'file'",
fileInput("file", "Select a txt file (encoding='UTF-8')")
),
colourInput("col", "Background color", value = "white"),
# Add a "draw" button to the app
actionButton(inputId = "draw", label = "Draw!")
),
mainPanel(
wordcloud2Output("cloud")
)
)
)
library(tidyverse)
library(jiebaR)
mixseg = worker()
server <- function(input, output) {
data_source <- reactive({
if (input$source == "own") {
(data <- as.data.frame(table(mixseg <= input$text)))
} else if (input$source == "file") {
f<-read_file(input$file$datapath)
if(is.null(f)){
return(NULL)
}else{
data <- as.data.frame(table(mixseg <=f))
}
}
return(data)
})
output$cloud <- renderWordcloud2({
input$draw
isolate(
wordcloud2(data_source(), backgroundColor =input$col))
})
}
There are multiple issues with your code.
wordcloud2 requires a data.frame including word and frequency count in two columns. Currently you are providing data_source() as input which is a reactive structure that returns a single character string.
You need to properly parse the textInput server-side, which means that you need to create a wordcloud2-suitable data.frame from the input provided through textAreaInput; in fact, using textAreaInput is probably not the best element to use here, as your input text is highly structured and textAreaInput is best used for unstructured text values, see ?textAreaInput. But let's continue with your textAreaInput for pedagogical purposes.
You should also include a check that ensures that the wordcloud only gets drawn if there is actually any data to use. We can do this using validate, see code below. Not including this check will result in a Warning: Error in [.data.frame: undefined columns selected.
Less of an issue but not helping your post in terms of clarity: You are not using input_file at all; ditto for colourInput.
Following is a minimal reproducible example (where I've removed the unnecessary parts)
library(shiny)
library(shinyjs)
library(wordcloud2)
ui <- fluidPage(
h1("Word Cloud"),
sidebarLayout(
sidebarPanel(
# Add radio buttons input
radioButtons(
inputId = "source",
label = "Word source",
choices = c(
"Use your own words" = "own",
"Upload a file" = "file")
),
conditionalPanel(
condition = "input.source == 'own'",
textAreaInput("text", "Enter comma-separated text", rows = 7)
),
conditionalPanel(
condition = "input.source == 'file'",
fileInput("file", "Select a file")
)
),
mainPanel(
wordcloud2Output("cloud")
)
)
)
server <- function(input, output) {
data_source <- reactive({
if (input$text != "")
as.data.frame(table(unlist(strsplit(input$text, "[, ]"))))
else
NULL
})
output$cloud <- renderWordcloud2({
validate(need(data_source(), "Awaiting data"))
wordcloud2(data_source(), backgroundColor = "white")
})
}
This produces e.g.
I am creating Shiny App and the purpose is to input text file and using udpipe library need to create wordcloud, annoate etc...
I am getting "inherits(x, "character") is not TRUE" when running the app. The problem comes from "Annotate" Tab as i am trying to return datatable from Server.R file
ui.R code:
shinyUI(
fluidPage(
##today's date
dateInput("date6", "Date:",
startview = "decade"),
##current time
h2(textOutput("CurrentTime")),
# Application title
titlePanel("UDPipe Text Analysis"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
# Input: for uploading a file ----
fileInput("file1", "Choose Text File"),
# Horizontal line ----
tags$hr(),
##checkbox input
checkboxGroupInput("upos",label = h4("Parts Of Speech to Show:"),
c("Adjective" = "ADJ",
"Propernoun" = "PROPN",
"Adverb" = "ADV",
"Noun" = "NOUN",
"Verb"= "VERB"),
selected = c("ADJ","NOUN","VERB"),
width = '100%'
#choiceNames =
# list(icon("Adjective"), icon("Adverb")),
#choiceValues =
#list("ADJ", "ADV")
)),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Overview",h4(p("Who deveoped this App")),
p("This app supports only text files. ", align = "justify"),
h4("Pupropse of this app"),
h4("what precaution to take")
),
tabPanel("Annotate",dataTableOutput('Annotate'))
)
)
server.R code
library(shiny)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
Dataset <- reactive({
if (is.null(input$file)) { return(NULL) } else
{
Data <- readlines(input$file1)
Data = str_replace_all(Data, "<.*?>", "")
return(Data)
}
})
output$Annotate <- renderDataTable(
{
english_model = udpipe_load_model("./english-ud-2.0-170801.udpipe")
x <- udpipe_annotate(english_model, x = Dataset)
return(x)
}
)
})
I am trying to return data table in output$Annotate variable. But its not working properly.
Replace your udpipe_annotate line of code to the following.
txt <- as.character(Dataset())
udpipe_annotate(ud_dutch, x = txt, doc_id = seq_along(txt))
This will avoid that you pass NULL to udpipe_annotate if no text data is loaded yet in your shiny app
I am working on a simple app that is supposed to ask for 1 (or more) unstructured text files, given by the user with fileInput. These files have all the same structure.
The idea is to make the cleaning/extraction on the background and give back the clean data to the user (ideally into a table).
I am fairly new using Shiny and the examples I have found basically indicate how to proceed when the file input is already in a clean and structured way.
Here is a simplified code that illustrates what I have done so far:
library(shiny)
shinyUI(fluidPage(
titlePanel(title = h2("Title", align = "left")),
sidebarLayout(position = "left",
sidebarPanel(h3("Data management window", align = "center"),
fileInput(inputId = "file_1",
label = "Select file 1")
),
mainPanel(
uiOutput(outputId = "tb")
)
)))
And here the server side:
shinyServer(function(input, output) {
input_file_1 <- reactive({
if(is.null(input$file_1)){
return("!! No data loaded !!")
}
readLines(input$file_1$datapath)
})
output$data_1 <- renderText({
fileText_1 <- paste(input_file_1(), collapse = "\n")
})
output$tb <- renderUI({
tabsetPanel(
tabPanel("Window 1",
br(),
tags$div(
tags$p("Summary infos : "),
tags$ul(
tags$li("Date calculation : ", Sys.Date()),
tags$li("Info 1: "),
tags$li("Info 2 : "),
tags$li("Info 3 : "),
br(),
verbatimTextOutput("data_1"))
))
)
})
})
At this stage I have managed to render the text of the file into the app. What I would like to do is to show in tabPanel some results obtained from the data extracted from the text file, like in the case of Sys.Date() but using values from the input file.
Do you have any ideas on how to proceed? Hope my question makes sense.
Your question is still too general, please more specific. But here is something to get you started. Using your server file and the iris dataset to make it easier, you can use the renderText() expression to extract the summary of one of your variable. And then you just add textOutput() expression in your tags$li("Info 1: ") argument.
Following a comment from OP, you could add a selectInput() that could help you pick one variable you want to summarise or extract information from. The code work as it is. Just replace iris by the file you will be loading.
ui = fluidPage(
titlePanel(title = h2("Title", align = "left")),
sidebarLayout(position = "left",
sidebarPanel(h3("Data management window", align = "center"),
fileInput(inputId = "file_1",
label = "Select file 1"),
uiOutput("Variable")
),
mainPanel(
uiOutput(outputId = "tb")
)
))
server = function(input, output) {
input_file_1 <- reactive({
if(is.null(input$file_1)){
return("!! No data loaded !!")
}
readLines(input$file_1$datapath)
})
output$data_1 <- renderText({
fileText_1 <- paste(input_file_1(), collapse = "\n")
})
output$Variable <- renderUI({
obj2 <- iris #replace by input_file_1()
selectInput("Variable", "Choose a variable", as.list(colnames(obj2)), multiple = FALSE)
})
output$summary1 <- renderPrint({
sub <- iris %>% select(input$Variable) #replace iris
a <- max(sub)
a
})
output$tb <- renderUI({
tabsetPanel(
tabPanel("Window 1",
br(),
tags$div(
tags$p("Summary infos : "),
tags$ul(
tags$li("Date calculation : ", Sys.Date()),
tags$li("Info 1: ", textOutput("summary1")),
tags$li("Info 2 : "),
tags$li("Info 3 : "),
br(),
verbatimTextOutput("data_1"))
))
)
})
}