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"))
))
)
})
}
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"
)
),
),
),
)
),
)
My Shiny app suddenly is behaving n a strange manner whereby it opens briefly and then closes itself. There are no errors in the console. On my Mac, the app works fine. However, on Windows, the issue arises.
My complete code can be seen below.
Subsequently, Mac, or Windows, when I am using my full dataset .csv file, (as opposed to my small dummy test dataset), I receive an error input string 1 is invalid UTF-8. I have tried all suggestions here How to identify/delete non-UTF-8 characters in R but without any success. I have also used the CLEAN() function in Excel itself, and also tried read.csv("dummyData.csv, encoding = "UTF-8"), neither of which worked. I'm out of ideas.
Any help on both these issues would be fantastic.
library(shiny)
library(tidyverse)
library(DT)
# Reading the main_data which the shiny app depends on, Please make sure that the column names are same
main_data <- read_csv("dummyData.csv")
ui <- fluidPage(
fluidRow(column(12, tags$h2("Assignment Details"))),
sidebarLayout(
sidebarPanel(
width = 3,
tags$div(
align = "center",
tags$img(src = "logo.png", width = "120", height = "120")
),
fluidRow(
column(12, align = "center", tags$br(), tags$b("Filter data")),
column(12, selectInput("sector_filter", "Sector", unique(main_data$Sector), multiple = TRUE)),
column(12, selectInput("client_filter", "Client", unique(main_data$`Client Name`), multiple = TRUE)),
column(12, selectInput("service_filter", "Service", unique(main_data$Service), multiple = TRUE)),
column(12, selectInput("cost_filter", "Cost", unique(main_data$`Cost (Ex-Vat)`), multiple = TRUE)),
column(12, align = "center", actionLink("reset_filters", "Clear Filters/Reset", style = "color: #962693"))
)
),
mainPanel(
width = 9,
tabsetPanel(
tabPanel(
"Assignment Description",
uiOutput("assignment_description")
),
tabPanel(
"Data Table",
DTOutput("data_table")
)
)
)
)
)
server <- function(input, output, session) {
# Creating a new empty tibble (which is basically a data.frame) for filtering based on the filters selected
filtered_data <- tibble()
observeEvent(input$reset_filters, {
updateSelectInput(session, "sector_filter", selected = "")
updateSelectInput(session, "client_filter", selected = "")
updateSelectInput(session, "service_filter", selected = "")
updateSelectInput(session, "cost_filter", selected = "")
})
# The observe code block will be triggered everytime any reactive object from the UI is changed (In this case out filters)
observe({
# If all the inputs are empty, We will just send the whole data without the filters. Else we filter
print(input$sector_filter)
print(input$client_filter)
print(input$service_filter)
print(input$cost_filter)
print(unique(main_data$Sector))
sector_filter_values <- input$sector_filter
client_filter_values <- input$client_filter
service_filter_values <- input$service_filter
cost_filter_values <- input$cost_filter
if (is.null(input$sector_filter)) {
sector_filter_values <- unique(main_data$Sector)
}
if (is.null(input$client_filter)) {
client_filter_values <- unique(main_data$`Client Name`)
}
if (is.null(input$service_filter)) {
service_filter_values <- unique(main_data$Service)
}
if (is.null(input$cost_filter)) {
cost_filter_values <- unique(main_data$`Cost (Ex-Vat)`)
}
filtered_data <<- main_data %>%
filter(Sector %in% sector_filter_values, `Client Name` %in% client_filter_values,
Service %in% service_filter_values, `Cost (Ex-Vat)` %in% cost_filter_values)
# This is where the assignment description will be rendered
output$assignment_description <- renderUI({
filtered_data$title <- paste0(filtered_data$`Client Name`, " - ", filtered_data$`Assignment Name`)
HTML(
paste0(
"<br><span style='color: #962693'>", filtered_data$title,
"</span><br>", filtered_data$`Assignment Description`, "<br>"
)
)
})
# This is where the table is rendered. To customise the table visit here https://rstudio.github.io/DT/
output$data_table <- renderDT({
datatable(
filtered_data %>% select(`Client Name`, `Assignment Name`, `Sector`, `Service`, `Cost (Ex-Vat)`)
)
})
})
# Whenever a row from the table is selected the Assignment Description must change regardless the filters selected
observeEvent(input$data_table_rows_selected, {
print(input$data_table_rows_selected)
filtered_data_from_table <- filtered_data[input$data_table_rows_selected, ]
print(filtered_data_from_table)
output$assignment_description <- renderUI({
filtered_data_from_table$title <- paste0(filtered_data_from_table$`Client Name`, " - ", filtered_data_from_table$`Assignment Name`)
HTML(
paste0(
"<br><span style='color: #962693'>", filtered_data_from_table$title,
"</span><br>", filtered_data_from_table$`Assignment Description`, "<br>"
)
)
})
})
}
shinyApp(ui = ui, server = server)
I took a small modification of the top answer here:
How to identify/delete non-UTF-8 characters in R
Simply converting my columns via the below code fixed my issues.
df$`Column Name`<- iconv(df$`Column Name`, to = "UTF-8")
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 would like to create a reactiveValues object in Shiny whose contents are defined the values contained in input widgets. I managed to do it, but my implementation seems to be unnecessarily clunky:
Create an empty reactiveValues object
Monitor when the value of input widgets changes with observeEvent
Assign values to the reactiveValues object using the non-reactive values from input widgets (isolate)
Here is an example:
ui <- fluidPage(
fluidRow(
column(2, radioButtons("main", label = "Main dish", choices = list("salad", "pasta"))),
column(2, radioButtons("desert", label = "Desert", choices = list("fruit", "cake"))),
column(8, actionButton("extra", "Louder!", style="background-color: #ffdb99"))
),
verbatimTextOutput("myorder")
)
server <- function(input, output, session) {
# 1. Create reactiveValues object
menuR <- reactiveValues()
# 2. Update values whenever widgets change
observeEvent(c(input$main, input$desert),
menuR[["meal"]] <- paste(c(isolate(input$main), isolate(input$desert)), collapse = " & ")
)
# 3. Perform operations on object values
observeEvent(input$extra,
menuR[["meal"]] <- paste0(toupper(menuR[["meal"]]), "!!!")
)
output$myorder <- renderText(menuR[["meal"]])
}
shinyApp(ui, server)
I would very much like to create the reactiveValues object directly like this (greatly simplifies the code above):
# Set values upon creation
menuR <- reactiveValues(meal = paste(c(input$main, input$desert), collapse = " & "))
which does not work because input$main is reactive...
I would have guessed that defining reactiveValues objects with values obtained from widgets would be a common thing to do.
Am I missing something?
Thanks for your help,
Hugo
You can do this by using reactive() instead of reactiveValues(). menuR is a reactive object that depends on the input values of main and desert. You can use it by calling menu() in your server code once it is defined. Also, this saves you from using isolate() as you can set the value of menu as a reactive object inside observeEvent().
library(shiny)
ui <- fluidPage(
fluidRow(
column(2, radioButtons("main", label = "Main dish", choices = list("salad", "pasta"))),
column(2, radioButtons("desert", label = "Desert", choices = list("fruit", "cake"))),
column(8, actionButton("extra", "Louder!", style="background-color: #ffdb99"))
),
verbatimTextOutput("myorder")
)
server <- function(input, output, session) {
menuR <- reactive({
paste(c(input$main, input$desert), collapse = " & ")
})
observeEvent(
input$extra,
menuR <- reactive({
toupper(paste(c(input$main, input$desert), collapse = " & "))
})
)
output$myorder <- renderText(menuR())
}
shinyApp(ui, server)
Edit
I misunderstood the problem earlier. You can use eventReactive() which monitors a input and changes when the user input changes. I have also added a default value for when the action button is yet to be clicked by the user.
library(shiny)
ui <- fluidPage(
fluidRow(
column(2, radioButtons("main", label = "Main dish", choices = list("salad", "pasta"))),
column(2, radioButtons("desert", label = "Desert", choices = list("fruit", "cake"))),
column(8, actionButton("extra", "Louder!", style="background-color: #ffdb99"))
),
verbatimTextOutput("myorder")
)
server <- function(input, output, session) {
# Set a 'default' value for the output
default.menuR <- reactive({
paste(c(input$main, input$desert), collapse = " & ")
})
menuR <- eventReactive(input$extra, {
toupper(paste(c(input$main, input$desert), collapse = " & "))
})
# Initial state of the button is 0, which displays 'default' value
output$myorder <- renderText({
if (input$extra == 0) {
return(default.menuR())
}
menuR()
})
}
shinyApp(ui, server)
Hope this helps!
I have taken Vishesh's suggestion and made it work. It does not look much different than my original example, and still requires repeating several lines of code.
It works by over-writing the reactive object each time one of the widgets changes.
library(shiny)
ui <- fluidPage(
fluidRow(
column(2, radioButtons("main", label = "Main dish", choices = list("salad", "pasta"))),
column(2, radioButtons("dessert", label = "dessert", choices = list("fruit", "cake"))),
column(8, actionButton("extra", "Louder!", style="background-color: #ffdb99"))
),
verbatimTextOutput("myorder")
)
server <- function(input, output, session) {
menuR <- reactive({
paste(c(input$main, input$dessert), collapse = " & ")
})
# Render text when app loads
output$myorder <- renderText(menuR())
# Update reactive object and re-render text (button 'extra')
observeEvent(
input$extra,{
temp <- toupper(paste(c(input$main, input$dessert), collapse = " & "))
menuR <<- reactive(temp)
output$myorder <- renderText(menuR())
}
)
# Update reactive object and re-render text (button 'main' or 'dessert')
observeEvent(c(input$main, input$dessert),{
menuR <- reactive(paste(c(input$main, input$dessert), collapse = " & "))
output$myorder <- renderText(menuR())
})
}
shinyApp(ui, server)
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