good day people,
I'm working on a word based reports automation task. These reports are basically some standard text, a dozen or so charts, some numeric/trend text values that I need to populated based on logic. The trend text, numeric values or charts are to be generated from backend database.
I'm able to produce a blank document with charts using database, the R packages I used are ReporteRs, RODBC, officer and corresponding dependency packages, ggplot2 for charts.
However what I would like to achieve is, have a word document template with some sort of placeholders where I can put the charts and these numeric values.
I've basic code as following
doc <- docx(title="my doc")
mychart <- ggplot(.....)
doc <- addPlot(doc, fun=print, x = mychart)
writeDoc(doc, filename)
Can anyone advise how to approach this task. I saw usage of template parameter in docx but I couldn't find suitable examples of putting values in placeholders or putting charts at particular placeholders inside Word document.
Hope I've explained it clearly, if not please let me know.
Ok I've figured out how to achieve it finally.
MS-Word allows putting placeholders in document and bookmark them so that values/data/images can be put in their place.
You can create a normal word document(not as word template) and add your static content in it along with bookmarked placeholders as per your requirements.
Please refer here to know how to add bookmarks , Word doesn't show existing bookmarks by default, to enable that go to File -> Options -> Advanced check Show bookmarks, you'll see [your_bookmark] thing in square brackets.
Next in R, try following code
doc <- docx(title="title", template="c://above_template.docx")
doc = addPlot(doc, x=myChartVariable, bookmark="your_chart_bookmark)
writeDoc(doc, "c://new_doc_file_path.docx:)
you should see new file with a chart substituted where you put its placeholder.
I would recommend using VBA for this, not R. Do some google-research on DocVariables in Word. Add some DocVariables to your Word template, keep your analytics in Excel, and then push what you have in Excel into the Word DocVariables. Use the script below, which runs in Excel, to make everything work.
Sub PushToWord()
Dim objWord As New Word.Application
Dim doc As Word.Document
Dim bkmk As Word.Bookmark
sWdFileName = Application.GetOpenFilename(, , , , False)
Set doc = objWord.Documents.Open(sWdFileName)
'On Error Resume Next
objWord.ActiveDocument.variables("BrokerFirstName").Value = Range("BrokerFirstName").Value
objWord.ActiveDocument.variables("BrokerLastName").Value = Range("BrokerLastName").Value
objWord.ActiveDocument.variables("Ryan").Value = Range("Ryan").Value
objWord.ActiveDocument.Fields.Update
'On Error Resume Next
objWord.Visible = True
End Sub
Finally, add a reference to Word, from Excel. Tools > References > Microsoft Word xxx Object Library.
Related
I am working in .NET Interactive (aka Polyglot) Notebooks in F# (but I believe the same would apply to C#). In my code, I am running functions that ultimately produce an F# list of floating point values, or alternatively might be an F# list of tuples which contain floating point values.
When I ask the notebook to display the variable, it shows the first 20 values and says ".. (more)." Ideally, I would like to either be able to download this data by pressing a link next to the table that's displayed, or alternatively, run some function that can copy the full data to the clipboard - similar to Pandas' to_clipboard function.
Is there a way to do this?
If you want to create a cell that, when run, copies the contents of a data frame to a clipboard, you can do this using the TextCopy package. For testing, I used the following (including also Deedle and extension for nicely rendering frames):
#i "nuget:https://www.myget.org/F/gregs-experimental-packages/api/v3/index.json"
#r "nuget:Deedle"
#r "nuget:Deedle.DotNet.Interactive.Extension,0.1.0-alpha9"
#r "nuget:TextCopy"
open Deedle
Let's create a sample data frame and a function to get its contents as CSV string:
let df =
Frame.ofRecords
[ for i in 0 .. 100 -> {| Name = $"Joe {i}" |} ]
let getFrameAsCsv (df:Frame<_, _>) =
let sb = System.Text.StringBuilder()
use sw = new System.IO.StringWriter(sb)
df.SaveCsv(sw)
sb.ToString()
To copy df to the clipboard, you can run:
TextCopy.ClipboardService.SetText(getFrameAsCsv df)
If you want to create a download link in the notebook output, this is also possible. You can use the HTML helper to output custom HTML and inside that, you can use the data: format to embed your CSV as a linked file in <a href=...> (as long as it is not too big):
let csv =
System.Convert.ToBase64String
(System.Text.UTF8Encoding.UTF8.GetBytes(getFrameAsCsv df))
HTML($"<a href='data:text/csv;name=file.csv;base64,{csv}'>Download CSV</a>")
I have been using officer package to create the respective PowerPoint decks, however at this moment, i would like to merge/ bind them all as one slide deck and was not able to figure out. Can someone guide me if there any package that helps to merge multiple PowerPoint decks into one.
I believe currently there are no functions or packages that do this in R, so I'll suggest you a few possible solutions that come to mind.
1: I believe you could use read_pptx() to read, say, a deck1 and a deck2 files. Then, loop through the slide indexes of deck2, and use those values to add_slide() into deck1. I think there's a function in officer called pptx_summary(), which converts a pptx R object into a tibble, but I'm not sure you could convert a tibble back to a pptx R object.
2: You could convert pptx files into pdf files, and use pdftools to join them.
When creating PowerPoint slides automatically via R (for example by using the PowerPoint export of R markdown), merging them with pre-manufactured fixed slides (for example explanations with elaborate visuals) may likely become necessary. As there seems not single-line solution so far, here's an incomplete answer to a 3-year-old question.
A look into the sources of OfficeR shows that the package works with a data structure and a temporary folder in the background that contains the XML files that are zipped in the XLSX file.
Copying slides, therefore, requires both: To update the structure, and to copy XML files and other ressources, eventually. Here is a very rough draft of how merging two PowerPoint files can work, based on the OfficeR classes.
merge_pptx = function(a, b, filename) {
# go through the slides of b
for (index in 1:length(source$slide$get_metadata())) {
# We need a new filename in the target's slide directory
new_slidename <- target$slide$get_new_slidename()
xml_file <- file.path(target$package_dir, "ppt/slides", new_slidename)
# Copy XML from source to new filename
orgFilename = source$slide$get_metadata()[index, "filename"]
newFilepath = paste(target$package_dir, newFilename, sep="/")
file.copy(orgFilename, xml_file)
# Not sure yet, what exactly this does
slide_info <- target$slideLayouts$get_metadata()[1,] # Use first best layout at the moment
layout_obj <- target$slideLayouts$collection_get(slide_info$filename)
layout_obj$write_template(xml_file)
# update presentation elements
target$presentation$add_slide(target = file.path("slides", new_slidename))
target$content_type$add_slide(partname = file.path("/ppt/slides", new_slidename))
# Add the slide to the collection
target$slide$add_slide(xml_file, target$slideLayouts$get_xfrm_data())
target$cursor <- target$slide$length()
}
print(target, target=filename)
}
source = read_pptx("One.pptx")
target = read_pptx("Two.pptx")
merge_pptx(source, target, "Combined.pptx")
Please note, that this is a draft only. It does not yet respect the different layouts for slides, not even speaking of different masters. Embedded files (images) are not yet copied.
The bulk of this function is inspired by the add_slide() function in the dir_slide class, see https://github.com/davidgohel/officer/blob/master/R/ppt_class_dir_collection.R
I often need to do a quick share of a table into an email or to a word or google document. I use the package clipr and built a function like this to put stuff on my clipboard:
function (x = .Last.value)
{
clipr::write_clip(x)
message("Value copied to clipboard")
}
When I do this with a table and paste it into the things mentioned above, the spacing is all messed up when it goes to a plain text editor (ie Spark, my email client) or to an editor that has table functionality (MS Word / Google Docs).
Is there a way to do an easy copy paste that preserves the table spacing for plain text? Or formats as a table in word/gdocs?
I regularly use the function below which elikesprogramming mentions in his answer on this question (How to solve "clipboard buffer is full and output lost" error in R running in Windows?) and it appears as a table object when pasting into Excel, Word or Outlook.
write.table(data, "clipboard-16384", sep = "\t", row.names = FALSE, quote = FALSE)
I am trying to post a table to my wordpress site using knit2wp. The table is created using kable and works fine. However, when I use the kableExtra package, and then knit2wp, the following line of text is added to my wordpress site:
<?xml version=“1.0” encoding=“UTF-8”?>
This line doesn't appear in the html output; only on the website.
I am looking to copy a function as per:
http://dwoll.de/rexrepos/posts/rerWorkflowWP.html
Then integrate the XML function:
post.content <- xmlOutputBuffer(header = NULL)
Or:
post.content <- xmlOutputDOM(xmlDeclaration = NULL)
Adding either of these will remove the heading, but also the tables. I am obviously new to XML. So looking for another solution.
Update:
Used xml2 to read the html output of knit2html. Then used the following functions:
xyz <- read_html("htmloutput.html")
x <- xml_find_all(xyz,".//p")
xml_remove(x, free = TRUE)
Saved as new html file, which I then entered into function as per link above.
I am using the RGoogleDocs package to upload a string of text to a document.
The following code is a minimal working example.
library(RGoogleDocs)
gpasswd = "mypassword"
auth = getGoogleAuth("example#gmail.com", gpasswd)
con = getGoogleDocsConnection(auth)
uploadDoc("test1", con, name = "d")
The problem: if I run this code twice two files named "d" appear.
In other words, the file is not replaced, even though in the function guide ?uploadDoc expected behaviour reads as
uploadDoc(content, con, name, type = as.character(findType(content)),
binary = FALSE, asText = FALSE, folder = NULL, ...)
-
name the name of the new document to be created (or the document to be replaced).
(Farrel Buchinsky brought this to my attention. It is often best to contact a package's author/maintainer if there is a problem as we don't necessarily follow both R-help and SO.)
Noah is right in saying just deleteDoc() and the uploadDoc().
We can do this in the uploadDoc() also.
I've just added a replace parameter to uploadDoc() (default is TRUE)
and that will (when I solve a possibly related bug)
a) move the current document, if it exists, to a temporary name
b) upload the new document to the target name,
c) delete the temporary document if the upload was successful
or, if not, move the temporary document back to the original name.
Something is up internally when testing this, but this should be in the next release.
I think the function guide here is a bit misleading. The uploadDoc function just creates a new document, and Google doesn't prevent you from having multiple docs named the same thing.
There is a stub in RGoogleDocs for updateDoc(), but it's been on the horizon for a while (last update of the package was 10/2009). I played for a few minutes, but would take some real digging to get it working.
Not a satisfying answer, but you could always just issue a deleteDoc() before re-uploading by the same name.