How to Create PDF file using Excel sheet using R? - r

I am searching for a way to create PDF files automatically using R. I saw people suggesting the RDCOMClient option, but it doesn't work for my PC.
How to create pdf file using excel sheet in R?
Input file: file.xlsx
Output file: file.pdf
Input:
Expected Output:
I thought to create a pdf file with the pdf() function for Data frame but I only managed to save the tables through the grid.table() function, but it is not creating exact pdf file.
pdf("file.pdf")
grid.table(df)
dev.off()
Does anyone have better solutions?

Here are two functions that you can consider :
library(RDCOMClient)
save_Excel_As_PDF <- function(path_To_Excel_File,
path_To_PDF_File)
{
xlApp <- COMCreate("Excel.Application")
xlWbk <- xlApp$Workbooks()$Open(path_Excel_File)
xlWbk$ExportAsFixedFormat(Type = 0, FileName = path_To_PDF_File)
xlWbk$Close()
xlApp$Quit()
}
save_Excel_Sheet_As_PDF <- function(path_To_Excel_File,
path_To_PDF_File,
sheet_Id)
{
xlApp <- COMCreate("Excel.Application")
xlWbk <- xlApp$Workbooks()$Open(path_Excel_File)
sheet <- xlWbk $Worksheets()$Item(sheet_Id)
sheet$Select()
# Type = 0 => PDF, Type = 1 => XPS
xlWbk[["ActiveSheet"]]$ExportAsFixedFormat(Type = 0, Filename = path_To_PDF_File,
IgnorePrintAreas = FALSE)
xlWbk$Close()
xlApp$Quit()
}
I use these functions at my job and they work very well.

Related

Saving multiple data-frames to single csv file using Shiny downloadHandler

I have an RShiny application where I'm displaying multiple data-frames across different tab-setted panels. I want to be able to write data-frames appearing across each panel to one csv file per panel. I am currently trying to render this using Shiny's downloadHandler option.
Did a little bit of research and found out I could use the sink() function to divert R output to a file.
Here's my attempt at trying to incorporate sink() into one such button on the server.R side
output$downloadDemographic <- downloadHandler(
filename = function() {
paste('Demographics', '.csv', sep='')
},
content = function(file) {
sink("Demographics.csv")
cat('Population Demographics')
write.csv(Population)
cat('Geography Demographics')
write.csv(Geography)
sink()
}
)
where Population and Geography are two data-frames with the same number of columns but different names.
The sink function automatically writes the above dataframes to a csv file 'Demographics.csv' into my working directory but the downloadHandler option on Shiny prompts the user to save the csv file on the fly. Kind of contradicting what I am trying to achieve here. I'm probably missing something or making an obvious mistake, I don't know.
Desired output - https://i.stack.imgur.com/yddrE.jpg
I could render multiple download buttons, write each of the data-frames to multiple csv files but some of my tab setted elements have as many as 8 data-frames and this would make the UI messy.
or
I could coerce multiple data-frames into a single one before writing to a csv file but they are all unequal sized dataframes and formatting them into the desired output would be a huge pain.
Any thoughts on how I could establish this any other way?
Thanks!
Other options:
Write an Excel workbook with one sheet per
dataframe
Zip together multiple csv
files
Here's a sample of both options using four dataframes from the R Datasets Package.
library(shiny)
library(xlsx)
shinyApp(
ui = fluidPage(
downloadButton("downloadExcelSheet", "Download Excel Workbook with Multiple Sheets"),
downloadButton("downloadZippedCSV", "Download zipped csv files")
),
server = function(input, output) {
#### Write an Excel workbook with one sheet per dataframe ####
output$downloadExcelSheet <- downloadHandler(
filename = function() {
"excelWorkbook.xlsx"
},
content = function(file) {
# write workbook and first sheet
write.xlsx(mtcars, file, sheetName = "mtcars", append = FALSE)
# add other sheets for each dataframe
listOtherFiles <- list(iris = iris,
airquality = airquality,
sleep = sleep)
for(i in 1:length(listOtherFiles)) {
write.xlsx(listOtherFiles[i], file,
sheetName = names(listOtherFiles)[i], append = TRUE)
}
}
)
#### Zip together multiple csv files ####
output$downloadZippedCSV <- downloadHandler(
filename = function() {
"zippedCSV.zip"
},
content = function(file) {
# go to temp dir to avoid permission issues
owd <- setwd(tempdir())
on.exit(setwd(owd))
# create list of dataframes and NULL value to store fileNames
listDataFrames <- list(mtcars = mtcars,
iris = iris,
airquality = airquality,
sleep = sleep)
allFileNames <- NULL
# loop through each dataframe
for(i in 1:length(listDataFrames)) {
# write each dataframe as csv and save fileName
fileName <- paste0(names(listDataFrames)[i], ".csv")
write.csv(listDataFrames[1], fileName)
allFileNames <- c(fileName, allFileNames)
}
# write the zip file
zip(file, allFileNames)
}
)
}
)

Exporting R shiny output to multiple sheets single excel.

I have built an app which gives an output data table based on the filter selected.
Suppose I change the filter 10 times and it gives me 10 results.
I need to store the results in 10 sheets in single excel.
For example:
Select filter option: A
Get the Output: Output1
Click on Download button.
Save results as sheetname: test1, excel: sample1.xlsx
Now I Select filter option: B
Get the Output: Output1
Click on Download button.
Save results as sheetname: test2, excel: sample1.xlsx
This is my code
output$downloadData1 <- downloadHandler(
filename = function()
{ paste('Sample','_', Sys.Date(), ".xlsx", sep="") },
content = function(file) {
write.xlsx(makeTable(), file, sheetName =input$sampleselect, row.names = FALSE , append = TRUE)
})
sampleselect is the filter selection and I am also passing this as the sheet name.
currently, this code throws out unique Excel files.
i.e For filter A: it creates an Excel Sample.xlsx and for filter B: it creates an Excel also named Sample.xlsx
Thanks in advance.

Highlighting text in PDF file using R

I wanted to highlighted some text in a PDF document using R. I want to search a PDF document for some text and highlight the text if found. I searched for packages which could do this.
pdftools and pdfsearch are packages which help in handling PDF documents. These packages mainly handle converting pdf to text and doing any sort of manipulation.
Is there a way in which we can highlight a PDF document using R?
I was able to highlight some keywords in a PDF with the following code. There are four steps :
Save wikipedia page to PDF;
Convert the PDF to word document with the Word Software (There is an OCR!!);
Highlight the keywords in the word document;
Save the word document as PDF.
library(RDCOMClient)
library(DescTools)
library(pagedown)
#############################################
#### Step 1 : Save wikipedia page as PDF ####
#############################################
chrome_print(input = "https://en.wikipedia.org/wiki/Cat",
output = "C:\\Text_PDF_Cat.pdf")
path_PDF <- "C:\\Text_PDF_Cat.pdf"
path_Word <- "C:\\Text_PDF_Cat.docx"
################################################################
#### Step 2 : Convert PDF to word document with OCR of Word ####
################################################################
wordApp <- COMCreate("Word.Application")
wordApp[["Visible"]] <- TRUE
wordApp[["DisplayAlerts"]] <- FALSE
doc <- wordApp[["Documents"]]$Open(normalizePath(path_PDF),
ConfirmConversions = FALSE)
doc$SaveAs2(path_Word)
doc_Selection <- wordApp$Selection()
######################################################
#### Step 3 : Highlight keywords in word document ####
######################################################
move_To_Beginning_Doc <- function(doc_Selection)
{
doc_Selection$HomeKey(Unit = wdConst$wdStory) # Need DescTools for wdConst$wdStory
}
highlight_Text_Regex_Word <- function(doc,
doc_Selection,
words_To_Highlight,
colorIndex = 7,
nb_Max_Word = 100)
{
for(i in words_To_Highlight)
{
move_To_Beginning_Doc(doc_Selection)
for(j in 1 : nb_Max_Word)
{
doc_Selection$Find()$Execute(FindText = i, MatchCase = FALSE)
doc_Selection_Range <- doc_Selection$Range()
doc_Selection_Range[["HighlightColorIndex"]] <- colorIndex
}
}
}
highlight_Text_Regex_Word(doc, doc_Selection,
words_To_Highlight = c("cat", "domestic", "quick"),
colorIndex = 7, nb_Max_Word = 100)
###############################################
#### Step 4 : Convert word document to pdf ####
###############################################
path_PDF_Highlighted <- "C:\\Text_PDF_Cat_Highlighted.pdf"
wordApp[["ActiveDocument"]]$SaveAs(path_PDF_Highlighted, FileFormat = 17) # FileFormat = 17 saves as .PDF
doc$Close()
wordApp$Quit() # quit wordApp

Shiny to output a function that generates a pdf file itself

I am trying to use Shiny to build an app with a function that output a pdf file. Specifically, the function I am trying to use is the msaPrettyPrint function from the msa package. It uses the texi2pdf function from the tools package to generate a pdf file.
For example, if you run the following code, you will generate a pdf called "myFirstAlignment.pdf" with an amino acid sequence alignment in your working directory.
# source("http://www.bioconductor.org/biocLite.R")
# biocLite("msa")
library(msa)
mySequenceFile <- system.file("examples", "exampleAA.fasta", package="msa")
mySequences <- readAAStringSet(mySequenceFile)
myFirstAlignment <- msa(mySequences)
msaPrettyPrint(myFirstAlignment, output="pdf", showNames="left",showLogo="top",consensusColor="BlueRed", logoColors="accessible area", askForOverwrite=FALSE)
I was wondering if there is a way to make the following code works? I think the problem might be because the output is already a pdf file. I want to see the pdf output on screen if possible. If not possible to see it on screen, where is the pdf file and if I can download it?
library(shiny)
runApp(list(
#Load the exmaple from the msa package.
mySequenceFile <- system.file("examples", "exampleAA.fasta", package="msa"),
mySequences <- readAAStringSet(mySequenceFile),
myFirstAlignment <- msa(mySequences),
# A simple shiny app.
# Is it possible to see the generated pdf file on screen?
ui = fluidPage(plotOutput('plot')),
server = function(input, output) {
output$plot <- renderPlot(msaPrettyPrint(myFirstAlignment, output="pdf", showNames="left",showLogo="top",consensusColor="BlueRed", logoColors="accessible area", askForOverwrite=FALSE))
}
))
One thing to mention is that this code needs LaTeX to work. You would need LaTeX to run the example.
Thanks a lot!
I was having issues running your example but this should work
library(shiny)
runApp(list(
#Load the exmaple from the msa package.
mySequenceFile <- system.file("examples", "exampleAA.fasta", package="msa"),
mySequences <- readAAStringSet(mySequenceFile),
myFirstAlignment <- msa(mySequences),
# A simple shiny app.
# Is it possible to see the generated pdf file on screen?
ui = fluidPage(downloadButton('downloadPDF')),
server = function(input, output) {
output$downloadPDF = downloadHandler(
filename = 'myreport.pdf',
content = function(file) {
out = msaPrettyPrint(
myFirstAlignment
, file = 'myreport.pdf'
, output="pdf"
, showNames="left"
, showLogo="top"
, consensusColor="BlueRed"
, logoColors="accessible area"
, askForOverwrite=FALSE)
file.rename(out, file) # move pdf to file for downloading
},
contentType = 'application/pdf'
)
}
))
Maybe you can use the msaPrettyPrint file argument to store the pdf locally, and then use this solution displaying a pdf from a local drive in shiny to put a pdf viewer in your application.
Thanks so much for the help from JackStat and Malanche. The following works for downloading the result!
library(shiny)
runApp(list(
#Load the exmaple from the msa package.
mySequenceFile <- system.file("examples", "exampleAA.fasta", package="msa"),
mySequences <- readAAStringSet(mySequenceFile),
myFirstAlignment <- msa(mySequences),
# A simple shiny app.
# Is it possible to see the generated pdf file on screen?
ui = fluidPage(downloadButton('downloadPDF')),
server = function(input, output) {
output$downloadPDF = downloadHandler(
filename = 'myreport.pdf',
content = function(file) {
msaPrettyPrint(
myFirstAlignment
, file = 'myreport.pdf'
, output="pdf"
, showNames="left"
, showLogo="top"
, consensusColor="BlueRed"
, logoColors="accessible area"
, askForOverwrite=FALSE)
file.rename("myreport.pdf", file) # move pdf to file for downloading
},
contentType = 'application/pdf'
)
}
))

Shiny Download File based on File Path

I have a file which i generate in shiny
The user clicks a button and the file should download. However nothing happens
The function export_report generates the excel file and saves it to a location. The function then passes back the file location to the download handler so it will download the file. The problem seems to be that it isnt being returned correctly. I have tested the function (export_report) outside of shiny and it returns everything perfectly so I'm clearly doing something wrong from the shiny perspective.
The file itself is created where it is supposed to be on the server because i can download it within RStudio and see it in the file explorer. Can anyone help
# UI Section
downloadButton("downloadRpt", "Download Report")
# Server Section
output$downloadRpt <- downloadHandler(
filename = function() {
mydf <- report()
dateRange <- input$dates_report
selection <- input$selection
myfile <- export_report (mydf, selection, dateRange)
},
content = function(file) {
file.copy(myfile, file)
}
)
I have seen other examples R Shiny: Download existing file which is what my code is based on
EDIT 1: Adding the export_report function with some fake data to run it
export_report <- function(mydf,selection,dateRange) {
# Template for where the template excel file is stored
myoutputTemplate <- '/home/shiny_tutorials/Save to Database/templates/output_template.xlsx'
start_date <- dateRange[1]
end_date <- dateRange[2]
date_range <- paste(start_date ,end_date, sep = " - " )
# Load workbook the template workbook
wb <- loadWorkbook(myoutputTemplate)
# write to the workbook the data frame
writeWorksheet(wb, mydf, sheet="Details",
startRow=8, startCol=2,
header=FALSE)
# add the the customer the user selected
writeWorksheet(wb, selection, sheet="Details",
startRow=3, startCol=3,
header=FALSE)
# date
writeWorksheet(wb, date_range, sheet="Details",
startRow=5, startCol=3,
header=FALSE)
# Create The file Name
filename <- paste(selection, Sys.Date(), sep = " - ") %>%
paste(.,"xlsx", sep = ".")
# removes the % sign and extra qoutes
filename <- gsub (pattern = '\'|%','', x = filename)
# output directory
myoutput <- paste('/home/shiny_tutorials/Save to Database/output/',
filename, sep = '')
# Save workbook
saveWorkbook(wb, myoutput)
# Return File Path
myoutput
}
To call the function you can use the data below
dateRange <- c("2011-09-23","2016-09-23")
selection = "COMPANY_A"
mydf <- iris
myfile <- export_report(mydf,selection,dateRange)
EDIT 2 I have now managed to get an error out of it. When i cat(myfile) in the filename = function() { section of the code i get the error after the correct file path has been returned
Warning in rep(yes, length.out = length(ans)) :
'x' is NULL so the result will be NULL
Warning: Error in ifelse: replacement has length zero
Stack trace (innermost first):
1: runApp
Error : replacement has length zero
This error is basically because my file path does not get passed to the segment myfile so
if someone can tell me how to get the filepath generated by my function to the server section of the code below, that should fix my problem
content = function(file) {
file.copy(myfile, file)
}
Thank you to everyone who commented and clarified my thinking a bit on how the download handler works.
In the end, i created a new function which split up the export function above
The new function i used is called generate_file() which simply returns the file name
generate_file_name <- function(selection) {
# Create The file Name
filename <- paste(selection, Sys.Date(), sep = " - ") %>%
paste(.,"xlsx", sep = ".")
# removes the % sign and extra qoutes
filename <- gsub (pattern = '\'|%','', x = filename)
# output directory
myoutput <- paste('/home/shiny_tutorials/Save to Database/output/',
filename, sep = '')
# Return File Path
myoutput
}
Then in the server side
output$downloadRpt <- downloadHandler(
filename = function() {
selection <- input$company
generate_file_name(selection)
},
content = function(file) {
mydf <- report()
dateRange <- input$dates_report
selection <- input$company
export_report(mydf,selection,dateRange)
myfile <- generate_file_name(selection)
file.copy(myfile, file)
}
)
This then finds the newly created file and exports it for the user
I just checked your problem with this example code and it worked:
output$downloadData <- downloadHandler(
filename = function() {
data <- mtcars
myfile <- "data.csv"
write.csv(data, myfile)
myfile
},
content = function(file) {
print(file) //prints: [...]\\Local\\Temp\\RtmpEBYDXT\\fileab8c003878.csv
file.copy(file, file)
}
)
myfile is the filename of the downloaded file. You cannot use it in file.copy as input, this variable is out of scope. It seems that R creates a temp file name (see the print()).
Try to use the filename function to define your path or a custom file name, and the write.csv in the content part. Example code:
output$downloadData <- downloadHandler(
filename = function() {
paste(<user_name or date for eg>, ".csv", sep="")
},
content = function(file) {
write.csv(data, file)
}
)
I noticed in your comment above, you have asked how the application would generate the correct file when used by multiple users. For this part, you need to use the session.
So if your business logic functions were to come from an R file called foo.R, the server code should look something like:
shinyServer(func = function(input, output, session) {
source("./foo.R", local=TRUE)
......
And this would separate out the session for each user, thereby generating files specific to each, when downloading. Hope this gives you some pointers.

Resources