- 📦 Using
recordPlot()withofficerneeds careful handling of plot windows and timing. - 🖼️ Exporting base R plots as image files works in more places.
- 🔄
ggplot2plots work well withofficerbecause of how they are built. - ⚙️ Inline
replayPlot()functions work best right away in the same R session where you made the plot. - 📄 Making plots for Word documents with
officerautomatically is possible using reliable methods.
Exporting Base R Plots with recordPlot and officer
Making Word or PowerPoint reports automatically from R is a big help for your work. But putting base R plots into these documents is not always easy, especially when using the officer package. While recordPlot() might seem like a clear choice for saving and moving plots, it can be tricky when used with body_add_plot(). Here, we look at how recordPlot() works, why it can be a problem with officer, and ways to export plots reliably. This includes making plots on the fly, saving them as images, and using ggplot2.
How recordPlot() and replayPlot() Work in R
The recordPlot() and replayPlot() functions let you save and show a base R plot again. Specifically:
recordPlot()saves everything shown on an open plot window.replayPlot()lets you show that saved plot again later, but only if the right plot settings are still there.
Basic Usage Example
plot(cars)
rec <- recordPlot()
# Later during the same session
replayPlot(rec)
It saves exact drawing steps linked to the current plot window. So, it only works with the R session and plot window used when you first made the plot.
Limits of recordPlot()
recordPlot() is useful when you are working interactively. But it has some big limits:
- ❌ The saved plot doesn't work well after the plot window closes.
- ❌ It cannot be moved to another R session (so, you can't save it and use it later).
- ❌ It doesn't give back a simple plot object that can be used by other plot programs.
- ❌ Showing the plot again might fail on servers or other systems that don't have a screen.
Understanding officer for Document Making
The officer R package lets you build Microsoft Word documents (.docx) and PowerPoint presentations (.pptx) in an organized, coded way. It's great for making reports automatically. You can add tables, pictures, and text.
Core officer Functions
Here are some of the functions used most often:
read_docx()andread_pptx()– Create new Word or PowerPoint files.body_add_par()– Add lines of text to Word documents.body_add_plot()– Add plots made on the fly to Word documents.body_add_img()– Put outside image files (PNG, JPEG, etc.) into documents.print()– Save the finished document to your computer.
This tool is very helpful for research you can check, automatic reports, and dashboards from tools like Shiny or R Markdown.
Why recordPlot() Doesn’t Work Directly with body_add_plot()
A common mistake happens when users try to put the result of recordPlot() straight into officer::body_add_plot(). They think the saved plot can go in like a picture or other item. In reality, body_add_plot() needs a function that can draw the plot again in a plot window.
Invalid Attempt
doc <- read_docx()
doc <- body_add_plot(doc, value = rec, width = 6, height = 5)
This approach gives an error or shows an empty space in the document because recordPlot() objects do not work with what body_add_plot() needs.
Valid Approach: Use a Plotting Function
doc <- body_add_plot(doc, value = function() plot(cars), width = 6, height = 5)
This works because body_add_plot() opens a new plot window (like PNG or EMF) on its own, runs the function, saves the picture, and puts it in the document.
Using replayPlot() Inside body_add_plot() to Export R Plots
To use recordPlot() with officer, you need to give it a function that calls replayPlot().
Example Workflow
library(officer)
plot(cars)
rec <- recordPlot()
doc <- read_docx()
doc <- body_add_plot(doc, value = function() replayPlot(rec), width = 6, height = 5)
print(doc, target = "report.docx")
Key Points
- ✅ Works only within the same session where you made the plot.
- ✅ Needs the original plot window settings to still be there.
- ❌ It will not work if the original plot window has closed (
dev.off()was called). - ❌ Often not dependable in R scripts that run on their own (e.g., Rscript or CI pipelines).
This way is good in some cases. But just using recordPlot() and replayPlot() can make things unsteady and act in unexpected ways in R tasks that change often.
When recordPlot() Fails with officer
Knowing when recordPlot() doesn't work can help in planning a safer way to export plots.
Common Errors
"plot.new has not been called yet": This usually means the saved plot does not have the right plot settings.- Blank plots in output: This might happen if you try to show an old or wrong plot on a closed window.
- Misalignment or cropped plots: This happens if the picture size does not match when trying to show the plot again with different settings.
- Crashes on servers: Plot programs (like X11) might not be available on servers or command-line tasks.
These errors show how delicate showing plots again can be, especially for tasks you want to repeat exactly or run automatically.
More Reliable Way: Save R Plots as Images
Instead of dealing with plot settings that disappear, you can save base R plots as images (usually PNGs) and use them again in officer documents.
Way to Export Plots as Images
# Save the plot to your computer
png("plot.png", width = 600, height = 400)
plot(cars)
dev.off()
# Add to Word document
doc <- read_docx()
doc <- body_add_img(doc, src = "plot.png", width = 6, height = 4)
print(doc, target = "output.docx")
Good Points
- ✅ You can fully control how clear the image is and its size.
- ✅ Works from R systems that run on their own or from scripts.
- ✅ No longer relies on specific plot settings or the R session.
- ✅ You can easily track changes to them or include them with reports.
This method works very well with automated building systems (CI/CD) or reporting steps that you need to repeat exactly.
Choosing the Right Export Method
The best way to do this depends on your setup and what you need.
Method 1: Inline with replayPlot()
This is good in projects where:
- The R session is interactive or short.
- Plots are made and exported in scripts that run step-by-step.
- You need to keep exact details when drawing (e.g., animations, smooth changes).
rec <- recordPlot()
doc <- body_add_plot(doc, value = function() replayPlot(rec), width = 6, height = 5)
Method 2: Using png() + body_add_img()
Use this when:
- Running code in live systems or on servers.
- You want to make plots that can be remade exactly later or to save them for a long time.
- Many plots are made with code.
png("summary.png", width = 800, height = 600)
plot(mtcars$mpg, col = "blue")
dev.off()
doc <- body_add_img(doc, src = "summary.png", width = 7, height = 5)
Exporting ggplot2 Plots with officer
Unlike base R's way of telling it what to draw step-by-step, ggplot2 uses plot objects. This makes it easier to pass plots around and draw them.
Example: Put a ggplot2 Plot in
library(ggplot2)
p <- ggplot(data = cars, aes(x = speed, y = dist)) + geom_point()
doc <- read_docx()
doc <- body_add_plot(doc, value = function() print(p), width = 6, height = 5)
Benefits of Using ggplot2
- ✅ Plot objects can be saved and used again in different R sessions.
- ✅ Needs less from plot programs.
- ✅ Works better in Shiny, RMarkdown, and server systems.
- ✅ Works more smoothly with
officer.
This makes ggplot2 fit better with making things automatic, doing research you can check, and making documents.
Fixing Plot Export Issues
You might run into problems when putting plots into Word or PPT using officer. Use this checklist:
- 🔎 Did you call
dev.off()too early? - 🔄 Are you trying to use a
recordPlot()object in different R sessions? - 🧱 Is your plotting function complete on its own (meaning, does it include
plot(), not justlines()orabline()calls)? - 🏃 Is your script running on its own without a display program like X11?
Plot functions that are well-made and can be tested will make sure plots are exported without trouble.
Best Ways for Steady Plot Tasks in R
Making reporting tools that work well and can handle more data in R needs careful planning for how plots are made:
- 📐 Make all plot sizes the same so they look consistent.
- 🧹 Clean up temporary images after use to keep your disk tidy.
- 📂 Use unique filenames (IDs, timestamps) for each plot when running many plots at once.
- 🧾 Keep plots and data together so you can always check them (for example, put them in a ZIP file or R Markdown bundle).
- ✅ Check plots by looking at them before putting them into automatic reports.
These practices will help as your reports get more complex and you make them more often.
Going to Big Reports: Use Images Instead of Redrawing
For big reports with many plots, drawing plots again on the fly with body_add_plot() can use a lot of computer memory and time.
Tip: Make plots into image files beforehand while you are working with data or making models, then add them using body_add_img(). This way of doing things in parts makes it run faster and more steadily, especially for long Word or PowerPoint files with many pictures.
Full Automation from Shiny or R Scripts
If you're making web reports that change or background scripts, combine plot creation and officer to make finished documents automatically:
doc <- read_docx()
doc <- body_add_par(doc, "Daily Summary", style = "heading 1")
doc <- body_add_plot(doc, value = function() hist(mtcars$hp), width = 6, height = 5)
print(doc, target = "daily_report.docx")
You can make automation even faster by using:
rmarkdown::render()for documents from templates.- Shiny download handlers for users to create reports.
- GitHub Actions or Jenkins pipelines for reports made on a schedule.
Using officer with PowerPoint and PDF Outputs
PowerPoint works much like Word. Use read_pptx() and related ph_with() methods.
pres <- read_pptx()
pres <- add_slide(pres, layout = "Title and Content", master = "Office Theme")
pres <- ph_with(pres, value = function() plot(cars), location = ph_location_fullsize())
print(pres, target = "deck.pptx")
For PDFs, use rmarkdown::pdf_document instead of officer. While recordPlot() still works, think about saving to images or using ggplot2 so it works with more programs.
Choosing the Right Tool for Exporting Plots
Choose your method and tool based on these needs:
| Use Case | Recommended Method |
|---|---|
| When working interactively | recordPlot() + inline replayPlot() |
| Scripts run on their own or on servers | Save as images and use body_add_img() |
| Plots made as objects that work well with other tools | Use ggplot2 + function call |
| Big documents with many plots | Make images in batches and put them in |
| Use again in different sessions or systems | Save to file or switch to ggplot2 |
Summary
Plot export in R, especially using base graphics, can be hard. But the officer package is flexible. Just pick the right way to export plots. Use recordPlot() only sometimes, and know that it only works in the session you made it in. For more reliable and bigger document making, image export or ggplot2 graphing are top choices.
Try different ways to handle your plot exports, and have fun plotting!
References
- grDevices package. (n.d.).
?recordPlot[Documentation]. R Core Team. - officer package. (n.d.).
?body_add_plot[Documentation]. CRAN. https://cran.r-project.org/package=officer