Add logo to ggplot2 in a loop

52 Views Asked by At

I'm trying to utilize the method outlined here to add a logo to a plot, but in a loop. It works fine for one plot, but in a loop it doesn't print as expected. Note that the first R logo is placed prior to anything else, and then is dropped from the last plot.

enter image description here

I'm utilizing it in quarto to put out as a html document, though I don't think that should matter with the code.

---
title: "Logo Plot Question"
format: 
  html:
    page-layout: full
editor: source
execute:
  echo: false
  warning: false
editor_options: 
  chunk_output_type: console
---

```{r}
# Load ggplot2
library(ggplot2)
library(grid)
library(magick)

# # Create data
data <- data.frame(
  name=c("A","B","C","D","E") ,
  value=c(25,49,36,18,45)
  )

logo <- magick::image_read("https://upload.wikimedia.org/wikipedia/commons/thumb/1/1b/R_logo.svg/1448px-R_logo.svg.png")

for (i in 1:2){

  print("Start plot")
  
p <- ggplot(data, aes(name, value)) + 
     geom_bar(stat = "identity", width = 1,  aes(fill = value)) +
     coord_polar(clip = "off") +
     scale_y_continuous(limits = c(-10, 50)) +
     theme_void() +
     theme(legend.position = "none") +
     labs(title = paste0("Plot ", i))


grid::grid.raster(logo, x = 0.5, y = 0.5, 
                  just = c('center', 'top'),
                  width = unit(0.5, 'inches'))
print(p)

# Does not work...
# p2 <- grid::grid.raster(logo, x = 0.5, y = 0.5, 
#                   just = c('center', 'top'),
#                   width = unit(0.5, 'inches'))
# 
# print(p2)

print("End plot")

}
```

Note: I've seen solutions that suggest using ggsave() to save as an image and then reimport in. I would like to shy away from this as I am creating a report and don't want hundreds of images sitting around.

2

There are 2 best solutions below

2
Allan Cameron On BEST ANSWER

I like to keep ggplot objects as ggplot objects. The linked article draws over an existing ggplot.

I would probably use a custom annotation in most cases, but this doesn't work with polar co-ordinates, so I would instead make a logo-only ggplot that I could add to any plot using the inset_element function from the patchwork package.

library(ggplot2)
library(grid)
library(magick)
library(patchwork)

data <- data.frame(
  name=c("A","B","C","D","E") ,
  value=c(25,49,36,18,45)
)

logo_plot <- ggplot() +
  theme_void() +
  annotation_custom(rasterGrob( x = 0.5, y = 0.5,
    image_read(paste0("https://upload.wikimedia.org/wikipedia/",
                      "commons/thumb/1/1b/R_logo.svg/",
                      "1448px-R_logo.svg.png")), 
    just = c('center', 'center'), width = unit(0.5, 'inches')))

for(i in 1:2) {
  
  cat("Here's plot", i, "\n")
  
  p <- ggplot(data, aes(name, value)) + 
    geom_bar(stat = "identity", width = 1,  aes(fill = value)) +
    coord_polar(clip = "off") +
    scale_y_continuous(limits = c(-10, 50)) +
    theme_void() +
    theme(legend.position = "none") +
    labs(title = paste0("Plot ", i)) +
    inset_element(logo_plot, 0, 0, 1, 1)
  
  print(p)
}

Now the Quarto output is:

enter image description here

0
Gambit On

My version of the code uses the lapply function to generate and print the plots, which eliminates the need for a for loop. The base plot is defined separately, and then customized within the lapply function for each plot. This makes the code more concise and easier to read.

# Load libraries
library(grid)
library(magick)
library(ggplot2)
library(patchwork)

# Define data
data <- data.frame(
  name = c("A", "B", "C", "D", "E"),
  value = c(25, 49, 36, 18, 45)
)

# Define logo plot
logo_plot <- ggplot() +
  theme_void() +
  annotation_custom(rasterGrob(x = 0.5, y = 0.5,
                               image_read(paste0("https://upload.wikimedia.org/wikipedia/",
                                                 "commons/thumb/1/1b/R_logo.svg/",
                                                 "1448px-R_logo.svg.png")), 
                               just = c('center', 'center'), width = unit(0.5, 'inches')))

# Define base plot
base_plot <- ggplot(data, aes(name, value)) + 
  geom_bar(stat = "identity", width = 1,  aes(fill = value)) +
  coord_polar(clip = "off") +
  scale_y_continuous(limits = c(-10, 50)) +
  theme_void() +
  theme(legend.position = "none")

# Generate plots
plots <- lapply(1:2, function(i) {
  base_plot +
    labs(title = paste0("Plot ", i)) +
    inset_element(logo_plot, 0, 0, 1, 1)
})

# Print plots
lapply(plots, print)