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
Related
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"
)
),
),
),
)
),
)
I am trying to run a shiny app with several scripted functions attached. I have a sidebar select input that accesses a variable which is only created after a file is uploaded and the "db_prep" R script is processed. The "db_prep" R script also combines elements of the "full_db" that is first loaded. I have tried to use renderUI to solve this problem but I cant identify where I am going wrong. Ideally, I would like to run the app, upload my file and then run my functions on the uploaded file and full_db to generate the output in the next boxplot tab.
Here is the ui:
#compiled db
full_db <- read.csv("./full_db.csv", header = TRUE, sep = ",", stringsAsFactors = FALSE)
# ui ----
ui <- fluidPage(
theme = shinytheme("superhero"),
titlePanel("Title"),
tabsetPanel(type = "tabs",
tabPanel("File Upload",
# 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")),
# Horizontal line ----
tags$hr(),
# Input: Checkbox if file has header ----
checkboxInput("header", "Header", TRUE),
# Input: Select separator ----
radioButtons("sep", "Separator",
choices = c(Comma = ",",
Semicolon = ";",
Tab = "\t"),
selected = ","),
# Input: Select quotes ----
radioButtons("quote", "Quote",
choices = c(None = "",
"Double Quote" = '"',
"Single Quote" = "'"),
selected = '"'),
# Horizontal line ----
tags$hr(),
# Input: Select number of rows to display ----
radioButtons("disp", "Display",
choices = c(Head = "head",
All = "all"),
selected = "head")
),
# Main panel for displaying outputs ----
mainPanel(
# Output: Data file ----
tableOutput("contents")
)
)
),
uiOutput("moreControls"),
# Main panel for displaying outputs ----
mainPanel(
h1("Actions"),
plotOutput("plot", width = "100%"))
))
Server:
# server ----
# Define server logic to plot various variables against
server <- function(input, output, session) {
#server logic for file upload tab
output$contents <- renderTable({
# input$file1 will be NULL initially. After the user selects
# and uploads a file, head of that data file by default,
# or all rows if selected, will be shown.
req(input$file1)
# when reading semicolon separated files,
# having a comma separator causes `read.csv` to error
tryCatch(
{
df_x <- read.csv(input$file1$datapath,
header = input$header,
sep = input$sep,
quote = input$quote)
if(is.null(input$file1)){
return(NULL)
}
},
error = function(e) {
# return a safeError if a parsing error occurs
stop(safeError(e))
}
)
if(input$disp == "head") {
return(head(df_x))
}
else {
return(df_x)
}
})
#server logic for boxplot tab
#required scripts & functions
source("db_prep.R")
source("box_75_test.R")
source("box_80_test.R")
source("box_85_test.R")
source("box_90_test.R")
source("box_95_test.R")
output$moreControls <- renderUI({
if(is.null(input$file1())) return()
tabPanel("Boxplot",
sidebarPanel("output.fileUploaded",
selectInput("variable", "Action:", unique(qc$Action)),
sliderInput("quantile", "Quantile Range:",
min = 75, max = 95, value = c(85), step = 5
)
))
})
# reprex ----
s_75 <- function(var) box_75_test(var)
s_80 <- function(var) box_80_test(var)
s_85 <- function(var) box_85_test(var)
s_90 <- function(var) box_90_test(var)
s_95 <- function(var) box_95_test(var)
fn <- reactive(get(paste0("s_", input$quantile)))
output$plot <- renderPlot(fn()(input$variable), height = 800, width = 800)
# ^^^ note the reactive value goes fn()(var)
}
shinyApp(ui, server)
The problem I was having was due to calling the source code which was also dependent on the creation of the data frame that could only be built after a csv file was uploaded. Initially, I was only able to create a data frame as an object after the shiny session had ended but I was able to fix this by wrapping my source files and functions in an observeEvent handler like this:
observeEvent(input$file1, {
req(df_x)
source("db_prep.R")
# reprex ----
s_75 <- function(var) box_75(var)
s_80 <- function(var) box_80(var)
s_85 <- function(var) box_85(var)
s_90 <- function(var) box_90(var)
s_95 <- function(var) box_95(var)
fn <- reactive(get(paste0("s_", input$quantile)))
output$plot <- renderPlot(fn()(input$variable), height = 800, width = 800)
There is probably a more elegant way to achieve this but hey it works.
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'm pretty new to shiny (being playing around for about a week). And I'm trying to create an app that takes and input tab-separated text file and perform several exploratory functions. In this case I'm presenting a very simplified version of that app just to highlight what I want to do in a specific case:
Problem:
If you try the app with the sample data (or any data in the same format) you can notice that the app effectively performs the default summary table (if selectInput="summarize", then output$sumfile), but when you try to select "explore", the previous table gets removed from the mainPanel, and outputs the full file (selectInput="explore",then output$gridfile) in the place where it would be as if selectInput="summarize" was still selected.
If you re-select "summarize", excelOutput("sumfile") gets duplicated on the mainPanel.
My goal is simple:
excelOutput("sumfile") when selectInput="summarize" ONLY and
excelOutput("gridfile") when selectInput="explore" ONLY
without placement issues or duplications on the mainPanel
So far I've tried:
inFile=input$df
if(is.null(inFile))
return(NULL)
if(input$show=="summarize")
return(NULL)
or
inFile=input$df
if(is.null(inFile))
return(NULL)
if(input$show=="explore")
return(NULL)
To control what shows up on the mainPanel, but with placement and duplication issues.
sample data:
#Build test data
testdat<-data.frame(W=c(rep("A",3),
rep("B",3),
rep("C",3)),
X=c(letters[1:9]),
Y=c(11:19),
Z=c(letters[1:7],"",NA),
stringsAsFactors = FALSE)
#Export test data
write.table(testdat,
"your/path/file.txt",
row.names = FALSE,
sep = "\t",
quote = FALSE,
na="")
shiny app (app.R):
library(shiny)
library(excelR)
#function to summarize tables
Pivot<-function(df){
cclass<-as.character(sapply(df,
class))
df.1<-apply(df,
2,
function(x) unlist(list(nrows = as.numeric(NROW(x)),
nrows.unique = length(unique(x))-(sum(is.na(x))+length(which(x==""))),
nrows.empty = (sum(is.na(x))+length(which(x==""))))))
df.2<-data.frame(df.1,
stringsAsFactors = FALSE)
df.3<-data.frame(t(df.2),
stringsAsFactors = FALSE)
df.3$col.class<-cclass
df.3$col.name<-row.names(df.3)
row.names(df.3)<-NULL
df.3<-df.3[c(5,4,1,2,3)]
return(df.3)
}
ui <- fluidPage(
ui <- fluidPage(titlePanel(title=h1("Summary generator",
align="center")),
sidebarLayout(
sidebarPanel(
h3("Loading panel",
align="center"),
fileInput("df",
"Choose file (format: file.txt)",
accept = c("plain/text",
".txt")),
selectInput("show",
"Choose what to do with file",
choices=c("summarize","explore")),
p("**'summarize' will output a summary of the selected table"),
p("**'explore' will output the full selected editable table"),
tags$hr()
),
mainPanel(
excelOutput("gridfile"),
excelOutput("sumfile")
))))
server <- function(input, output) {
dat<-reactive({
fp<-input$df$datapath
read.delim(fp,
quote="",
na.strings="\"\"",
stringsAsFactors=FALSE)
})
#get summary
output$sumfile<-renderExcel({
inFile=input$df
if(is.null(inFile)) #if fileInput is empty return nothing
return(NULL)
if(input$show=="explore") #if selectInput = "explore" return nothing
return(NULL)
dat.1<-data.frame(dat())
dat.2<-Pivot(dat.1)
excelTable(dat.2,
defaultColWidth = 100,
search = TRUE)
})
#get full file
output$gridfile<-renderExcel({
inFile=input$df
if(is.null(inFile)) #if fileInput is empty return nothing
return(NULL)
if(input$show=="summarize") #if selectInput = "summarize" return nothing
return(NULL)
dat.1<-data.frame(dat())
excelTable(dat.1,
defaultColWidth = 100,
search = TRUE)
})
}
shinyApp(ui = ui, server = server)
One way to do what you want is to use observeEvent for your inputs input$show and input$df and renderExcel based on your selection of `input$show. Here is an updated version for your code:
library(shiny)
library(excelR)
#function to summarize tables
Pivot<-function(df){
cclass<-as.character(sapply(df,
class))
df.1<-apply(df,
2,
function(x) unlist(list(nrows = as.numeric(NROW(x)),
nrows.unique = length(unique(x))-(sum(is.na(x))+length(which(x==""))),
nrows.empty = (sum(is.na(x))+length(which(x==""))))))
df.2<-data.frame(df.1,
stringsAsFactors = FALSE)
df.3<-data.frame(t(df.2),
stringsAsFactors = FALSE)
df.3$col.class<-cclass
df.3$col.name<-row.names(df.3)
row.names(df.3)<-NULL
df.3<-df.3[c(5,4,1,2,3)]
return(df.3)
}
ui <- fluidPage(
ui <- fluidPage(titlePanel(title=h1("Summary generator",
align="center")),
sidebarLayout(
sidebarPanel(
h3("Loading panel",
align="center"),
fileInput("df",
"Choose file (format: file.txt)",
accept = c("plain/text",
".txt")),
selectInput("show",
"Choose what to do with file",
choices=c("summarize","explore")),
p("**'summarize' will output a summary of the selected table"),
p("**'explore' will output the full selected editable table"),
tags$hr()
),
mainPanel(
excelOutput("gridfile"),
excelOutput("sumfile")
))))
server <- function(input, output) {
dat<-reactive({
fp<-input$df$datapath
read.delim(fp,
quote="",
na.strings="\"\"",
stringsAsFactors=FALSE)
})
observeEvent({
input$show
input$df
}, {
inFile=input$df
if(is.null(inFile)) #if fileInput is empty return nothing
return(NULL)
if(input$show=="explore") {
output$gridfile<-renderExcel({
dat.1<-data.frame(dat())
excelTable(dat.1,
defaultColWidth = 100,
search = TRUE)
})
}
if(input$show=="summarize") {
output$sumfile<-renderExcel({
dat.1<-data.frame(dat())
dat.2<-Pivot(dat.1)
excelTable(dat.2,
defaultColWidth = 100,
search = TRUE)
})
}
})
}
shinyApp(ui = ui, server = server)
Hope it helps!
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"))
))
)
})
}