I am trying to create an shiny app that uploads an image and then does OCR. The upload part seems to work but the OCR gives an error "Error: path must be URL, filename or raw vector" Any help is appreciated.
On another but related note, is anyone familiar with the implementation of MSER algorithm in R? I know I can call the python implementation through R.
library(shiny)
library(magick)
library(magrittr)
ui <- shinyUI(fluidPage(
titlePanel('Test Code'),
sidebarLayout(
sidebarPanel(
fileInput(inputId = 'files',
label = 'Select an Invoice',
multiple = FALSE,
accept=c('image/png', 'image/jpeg')),
imageOutput('images')
),
mainPanel(
textOutput('extracted')
)
)
))
server <- shinyServer(function(input, output) {
output$files <- renderTable(input$files)
files <- reactive({
files <- input$files
files$datapath <- gsub("\\\\", "/", files$datapath)
files
})
output$extracted<-renderText({
text <- image_read(list(src = files()$datapath[1])) %>%
image_resize("2000") %>%
image_convert(colorspace = 'gray') %>%
image_trim() %>%
image_ocr()
cat(text)
})
output$images <- renderImage({
list(src = files()$datapath[1],
height = 800,
width = 600,
alt = "Upload an Invoice in an image format")
}, deleteFile = FALSE)
}
)
shinyApp(ui=ui,server=server)
You need to fix output$extracted as follows:
output$extracted <- renderText({
if (is.null(input$files)) return(NULL)
# Fix file path
text <- image_read(files()$datapath[1]) %>%
image_resize("2000") %>%
image_convert(colorspace = 'gray') %>%
image_trim() %>%
image_ocr()
# Print to the console
cat(text)
# Return value to be rendered in Shiny
text
})
Related
I have an R script that loops through a folder of csv files, transforms them, and then writes several csv files once completed.
I want users to be able to use an input form to select various files before the R script runs. I have never used Shiny before, and I cannot figure out the best way to do this. Here is what I have come up with so far:
UI
library(shiny)
library(shinyjs)
fieldsMandatory <- c("calDataImport")
appCSS <- ".mandatory_star { color: red; }"
labelMandatory <- function(label) {
tagList(
label,
span("*", class = "mandatory_star")
)
}
ui <- fluidPage(
shinyjs::useShinyjs(),
shinyjs::inlineCSS(appCSS),
options(shiny.maxRequestSize = 30 * 1024^2),
titlePanel("Setup"),
sidebarLayout(
sidebarPanel(
fileInput("calDataImport", labelMandatory("Choose CSV File for Calibration Data"),
multiple = FALSE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv")),
tags$hr(),
shinyDirButton("ticLoc", "Choose Sample Folder", "Upload"),
tags$hr(),
# Output: Go and Download----
downloadButton('submit', 'Select Save Location and Go', class= "action"),
# CSS style for the download button ----
tags$style(type='text/css', "#downloadFile { width:100%; margin-top: 35px;}")
),
mainPanel()
)
)
Server
server <- function(input, output) {
observe({
# check if all mandatory fields have a value
mandatoryFilled <-
vapply(fieldsMandatory,
function(x) {
!is.null(input[[x]]) && input[[x]] != ""
},
logical(1))
mandatoryFilled <- all(mandatoryFilled)
# enable/disable the submit button
shinyjs::toggleState(id = "submit", condition = mandatoryFilled)
})
# dir
shinyDirChoose(input, 'ticLoc', roots = c(home = '~'), filetypes = c('xlsx', 'csv'))
ticLoc <- reactive(input$ticLoc)
output$ticLoc <- renderPrint(ticLoc())
# path
path <- reactive({
home <- normalizePath("~")
file.path(home, paste(unlist(ticLoc()$path[-1]), collapse = .Platform$file.sep))
})
# files
calDataImport <- reactive({
inFile <- input$calDataImport
if (is.null(inFile)) return(NULL)
calDataImport <- read.csv(inFile$datapath, header = TRUE)
calDataImport
})
# Download handler in Server
output$submit <- downloadHandler(
filename = function() {
paste('RAPTOR_Output', Sys.Date(), '.zip', sep='')
},
content = function(con) {
owd <- setwd(tempdir())
on.exit(setwd(owd))
outputFiles <- NULL;
################ INSERTING STANDARD R SCRIPT HERE ##########
# [necessary libraries here]
# [functions defined here]
if("CAS#" %in% colnames(calDataImport)){names(calDataImport)[names(calDataImport) == 'CAS#']<-"CAS Number"}
if("Component RT" %in% colnames(calDataImport)){names(calDataImport)[names(calDataImport) == 'Component RT']<-"Ret. Time"}
outputFileName <- paste("calDataImport", "csv", sep = ".")
write.csv(calDataImport, outputFileName, row.names = FALSE)
outputFiles <- c(outputFileName,outputFiles)
setwd(ticLoc)
files <- list.files(pattern = "csv")
filesFull <- list.files(pattern = "csv", full.names = TRUE)
for (i in 1:length(files)) {
fileName <- str_split(files[i], "\\.", n=2)[[1]][1]
rawData <- read.csv(paste(fileName, str_split(files[i], "\\.", n=2)[[1]][2], sep="."), check.names=FALSE)
# [more transforming script here]
outputFileName <- paste(fileName, "_Annotated",".csv", sep = "")
write.csv(annotatedData, outputFileName, row.names = FALSE)
outputFiles <- c(outputFileName,outputFiles)
}
################### END ############
#create the zip file
zip(con,outputFiles)
})
}
# Create Shiny app ----
shinyApp(ui, server)
What I have here doesn't seem to work. I get the following error:
Warning: Error in UseMethod: no applicable method for 'filter' applied to an object of class "c('reactiveExpr', 'reactive', 'function')"
[No stack trace available]
So my question is, how can I make this work? My standard R script that I am inserting is nearly 2000 lines, so I would rather not have to go through and adjust the script if possible.
Thank you so much for any insight you can provide!
This is a shiny app letting the user to upload multiple csv files. Then, the app reads each csv file and then calculates some properties, which will be displayed on the app. Please note the option multiple = TRUE in fileInput:
library(tidyverse)
library(shiny)
ui <- fluidPage(
fileInput(
inputId = "files",
label = "Upload tables",
placeholder = "No files selected.",
multiple = TRUE,
accept = c(
"text/csv",
"text/comma-separated-values,text/plain",
".csv"
)
),
tableOutput("table")
)
server <- function(input, output, session) {
output$table <- renderTable({
req(input$files %>% nrow() > 0)
input$files %>%
as_tibble() %>%
mutate(data = datapath %>% map(read_csv)) %>%
transmute(
datapath,
nrow = data %>% map_int(nrow),
colnames = data %>% map_chr(~ .x %>%
colnames() %>%
paste0(collapse = ", "))
)
})
}
shinyApp(ui, server)
Here I uploaded 2 csv files with the content of the R objects iris and mpg:
I do not know how your script is structured, but the uploaded files are in the directory dirname(input$files$datapath[[1]]).
I am writing a shiny app which:
creates a gt table
saves the gt table as an image (temporary file)
passes that image into a word doc using {officer} package
I am having difficulty with the image creation .... any help appreciated... here is my reprex
library(shiny)
library(gt)
library(dplyr)
ui <- fluidPage(
downloadButton("report", "Generate Report")
)
server <- function(input, output, session) {
my_table <- render_gt(
mtcars[1:5,1:5] %>%
gt()
)
my_image <-reactive({
outfile <- tempfile(fileext='.png')
gtsave(my_table, outfile, width = 400, height = 300)
})
output$report <- downloadHandler(
filename = function() {
"download.docx"
},
content = function(file) {
print(read_docx() %>%
body_add_img(my_image()),
target = file)
},
contentType = "docx"
)
}
shinyApp(ui, server)
There are several issues with your code:
You use render_gt instead of reactive.
Your reactive my_image does not return the name of the temporary file which is needed to add it to the docx. Additionally, as my_table is or should be a reactive use my_table()
In gtsave use vwidth and vheight. See ?webshot::webshot.
In officer::body_add_img you have to set a width and height in inches.
Reproducible code:
library(shiny)
library(gt)
library(dplyr)
library(officer)
ui <- fluidPage(
downloadButton("report", "Generate Report")
)
server <- function(input, output, session) {
my_table <- reactive({
mtcars[1:5, 1:5] %>%
gt()
})
my_image <- reactive({
outfile <- tempfile(fileext = ".png")
gtsave(my_table(), outfile, vwidth = 400, vheight = 300)
outfile
})
output$report <- downloadHandler(
filename = function() {
"download.docx"
},
content = function(file) {
read_docx() %>%
body_add_img(my_image(), width = 4, height = 3) %>%
print(target = file)
},
contentType = "docx"
)
}
shinyApp(ui, server)
As I am new to R shiny, please go easy on me:
I have found this code useful: https://community.rstudio.com/t/download-dataset-filtered-in-shiny-input/75770. This code takes Iris data and filters based on the column 'Species'
In order to get the filtering results after uploading my own data via fileInput() I made some adjustments to the code above. I am trying to filter data using the column 'Type', but I am receiving the below-mentioned error.
Error:
object 'file1' not found
csv data:
ID Type Range
21 A1 100
22 C1 200
23 E1 300
code:
library(tidyverse)
library(shiny)
library(DT)
library(shinyWidgets)
ui <- fluidPage(
#setBackgroundColor(color = c("#66e0ff", "#00a3cc", "#003d4d")),
h1("Data"),
sidebarLayout(
sidebarPanel(fileInput("file1", label = "Choose species"),
downloadButton("download1","Download entire Table as csv")),
mainPanel(h4("Table 1: Iris"),
dataTableOutput("csv_dto")
)
))
server <- function(input, output, session) {
output$csv_dto <- renderTable({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
read.csv(file$datapath, header = input$header)
})
thedata <- reactive({
file$datapath %>%
filter(Type == input$Type)
})
output$type_dto <- renderDataTable({
thedata() %>%
datatable(extensions = 'Buttons',
options = list(
#Each letter is a dif element of a datatable view, this makes buttons the last thing that's shown.
buttons = c("copy", "csv", "pdf")),
filter = list(
position = 'top'),
rownames = FALSE)
})
output$download1 <- downloadHandler(
filename = function() {
paste("type_", Sys.Date(), ".csv", sep="")
},
content = function(file) {
write.csv(thedata(), file)
}
)
}
shinyApp(ui, server)
could someone help me fix this issue?
I can't help you with the PDF output but to get you started: You have to do some adjustments of the code in the examples from ?fileInput.
Instead of renderTable use reactive. Also do not assign to an output. Instead of dataTableOutput("csv_dto") use dataTableOutput("type_dto") in the UI.
library(tidyverse)
library(shiny)
library(DT)
library(shinyWidgets)
ui <- fluidPage(
# setBackgroundColor(color = c("#66e0ff", "#00a3cc", "#003d4d")),
h1("Data"),
sidebarLayout(
sidebarPanel(
fileInput("file1", label = "Choose species"),
downloadButton("download1", "Download entire Table as csv")
),
mainPanel(
h4("Table 1: Iris"),
dataTableOutput("type_dto")
)
)
)
server <- function(input, output, session) {
csv_dto <- reactive({
file <- input$file1
ext <- tools::file_ext(file$datapath)
req(file)
validate(need(ext == "csv", "Please upload a csv file"))
read.csv(file$datapath)
})
thedata <- reactive({
csv_dto() %>%
filter(Type == input$Type)
})
output$type_dto <- renderDataTable({
thedata() %>%
datatable(
extensions = "Buttons",
options = list(
# Each letter is a dif element of a datatable view, this makes buttons the last thing that's shown.
buttons = c("copy", "csv", "pdf")
),
filter = list(
position = "top"
),
rownames = FALSE
)
})
output$download1 <- downloadHandler(
filename = function() {
paste("type_", Sys.Date(), ".csv", sep = "")
},
content = function(file) {
write.csv(thedata(), file)
}
)
}
shinyApp(ui, server)
I use Timevis package.
first of all I read an excel file with missions.
In my code the user can see all the missions on a time line, and he can edit/add/remove any missions.
after the user make a change I can see the update table below.
I want to save to my excel file every update that the user make.
this is my code:
library(shiny)
library(timevis)
library(readxl)
my_df <- read_excel("x.xlsx")
data <- data.frame(
id = my_df$id,
start = my_df$start,
end = my_df$end,
content = my_df$content
)
ui <- fluidPage(
timevisOutput("appts"),
tableOutput("table")
)
server <- function(input, output) {
output$appts <- renderTimevis(
timevis(
data,
options = list(editable = TRUE, multiselect = TRUE, align = "center")
)
)
output$table <- renderTable(
input$appts_data
)
}
shinyApp(ui, server)
You can use actionButton/ observe to call saveworkbook (package openxlsx) to save your changes. Technically you are not saving these changes, but replacing the file with an identical file containing the changes.
library(shiny)
library(openxlsx)
library(timevis)
library(readxl)
my_df <- read_excel("x.xlsx")
data <- data.frame(
id = my_df$id,
start = my_df$start,
end = my_df$end,
content = my_df$content
)
mypath = paste0(getwd(), "/x.xlsx") # Path to x.xlsx
ui <- fluidPage(
timevisOutput("appts"),
tableOutput("table"),
actionButton("save", "Save")
)
server <- function(input, output) {
output$appts <- renderTimevis(
timevis(
data,
options = list(editable = TRUE, multiselect = TRUE, align = "center")
))
observeEvent(input$save,
{
my_df<- createWorkbook()
addWorksheet(
my_df,
sheetName = "data"
)
writeData(
wb = my_df,
sheet = "data",
x = input$appts_data,
startRow = 1,
startCol = 1
)
saveWorkbook(my_df, file = mypath,
overwrite = TRUE)
})
output$table <- renderTable(
input$appts_data
)
}
shinyApp(ui, server)
I have created a leaflet map in a Shiny application. Now I need a download button, so that the user can download the currently shown map including all markers, polygons etc. as a pdf file.
I have found this solution how to save a leaflet map in R: How to save Leaflet in R map as png or jpg file?
But how does it work in Shiny? I kept the example code simple, but think of it, as if there were a lot of changes to the map via leafletProxy() before the user wants to save the map as a pdf.
This is my try, but it's not working.
server.R
library(shiny)
library(leaflet)
library(devtools)
install_github("wch/webshot") # first install phantomjs.exe in your directory
library(htmlwidgets)
library(webshot)
server <- function(input, output){
output$map <- renderLeaflet({
leaflet() %>% addTiles()
})
observe({
if(input$returnpdf == TRUE){
m <- leafletProxy("map")
saveWidget(m, "temp.html", selfcontained = FALSE)
webshot("temp.html", file = "plot.pdf", cliprect = "viewport")
}
})
output$pdflink <- downloadHandler(
filename <- "map.pdf",
content <- function(file) {
file.copy("plot.pdf", file)
}
)
}
ui.R
ui <- fluidPage(
sidebarPanel(
checkboxInput('returnpdf', 'output pdf?', FALSE),
conditionalPanel(
condition = "input.returnpdf == true",
downloadLink('pdflink')
)
),
mainPanel(leafletOutput("map"))
)
I have updated my previous answer to make it more clear and illustrate how to use mapshot from package mapview.
Moreover, following Jake's question below, I noticed that it might be necessary to specify a link to a tile (within addTiles), or the map might be downloaded with a grey background.
Server
server = function(input, output){
mymap <- reactive({
# here I have specified a tile from openstreetmap
leaflet() %>% addTiles('http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png')
})
output$map <- renderLeaflet({
mymap()
})
# function with all the features that we want to add to the map
myfun <- function(map){
addCircles(map,12.5,42,radius=500) %>% addMarkers(12,42,popup="Rome")
}
observe({
leafletProxy("map") %>% myfun()
})
# map that will be downloaded
mapdown <- reactive({
# we need to specify coordinates (and zoom level) that we are currently viewing
bounds <- input$map_bounds
latRng <- range(bounds$north, bounds$south)
lngRng <- range(bounds$east, bounds$west)
mymap() %>% myfun() %>% setView(lng = (lngRng[1]+lngRng[2])/2, lat = (latRng[1]+latRng[2])/2, zoom = input$map_zoom)
})
output$map_down <- downloadHandler(
filename = 'mymap.pdf',
content = function(file) {
# temporarily switch to the temp dir, in case you do not have write
# permission to the current working directory
owd <- setwd(tempdir())
on.exit(setwd(owd))
# using saveWidget and webshot (old)
saveWidget(mapdown(), "temp.html", selfcontained = FALSE)
webshot("temp.html", file = file, cliprect = "viewport")
# using mapshot we can substitute the above two lines of code
# mapshot(mapdown(), file = file, cliprect = "viewport")
}
)
}
UI
ui <- fluidPage(
sidebarPanel(
checkboxInput('returnpdf', 'output pdf?', FALSE),
conditionalPanel(
condition = "input.returnpdf == true",
downloadButton('map_down')
)
),
mainPanel(leafletOutput("map"))
)