I long struggled with a convenient means of adding images, primarily
logos, to maps and charts made in ggplot
. All the approaches just
seemed clunky, it was hard to size the and place the logo, or clipping
had to be turned off, or the plot had to be saved and then reloaded to
add the logo.
Then I came across the ggpmisc
package by Pedro Aphalo
(https://docs.r4photobiology.info/ggpmisc/) which has a couple really
nice functions geom_grob_npc
and geom_plot_npc
that make adding
images/logos/ggplot objects to ggplot maps and charts so simple. Below I
illustrate a simple wrapper for easy logo placement.
Quick function that serves as a wrapper around ggpmisc::geom_grob_npc
for placing images or logos on ggplot objects. I have used this for
adding objects (such a context mini-globes) to maps, and logos to both
maps and charts The npc
functionality is really nice for relative
placement and sizing is easy. Note: The real breakthrough here is
nothing I have written, but the really useful ggpmisc
package.
library(png)
library(ggplot2)
library(dplyr)
library(palmerpenguins)
library(tibble)
library(ggpmisc)
Lots of extraneous fluff in here for positioning and differential
positioning for maps and charts. I have found this useful, but all of
this is really just a wrapper around geom_grob_npc
add_image <- function(plot_object,
image_object,
img_rel_size = 0.3,
xloc = NA,
yloc = NA,
img_position = "lowerright",
img_just = "inside") {
# is it a map or a chart?
is_map <- "crs" %in% names(plot_object$coordinates)
image_ <- image_object
# ------------------------------------
# CHARTS:
# specify logo location (which corner)
# ------------------------------------
if (is_map == FALSE) {
if (is.na(xloc) & is.na(yloc)) {
if (img_position == "upperleft") {
x_ <- 0
y_ <- 1
} else if (img_position == "upperright") {
x_ <- 1
y_ <- 1
} else if (img_position == "lowerright") {
x_ <- 1
y_ <- 0
} else if (img_position == "lowerleft") {
x_ <- 0
y_ <- 0
} else if (img_position == 'center') {
x_ <- 0.5
y_ <- 0.5
} else {
break
}
} else if (!is.na(xloc) & !is.na(yloc)) {
x_ <- xloc
y_ <- yloc
} else {
break
}
# ------------------------------------
# specify logo justification
# ------------------------------------
if (img_just == "center") {
vjust_ <- "center"
hjust_ <- "center"
}
if (img_just == "outside") {
if (img_position == "upperleft") {
vjust_ <- "bottom"
hjust_ <- "left"
} else if (img_position == "upperright") {
vjust_ <- "bottom"
hjust_ <- "right"
} else if (img_position == "lowerright") {
vjust_ <- "top"
hjust_ <- "right"
} else if (img_position == "lowerleft") {
vjust_ <- "top"
hjust_ <- "left"
}
}
if (img_just == "inside") {
if (img_position == "upperleft") {
vjust_ <- "top"
hjust_ <- "left"
} else if (img_position == "upperright") {
vjust_ <- "top"
hjust_ <- "right"
} else if (img_position == "lowerright") {
vjust_ <- "bottom"
hjust_ <- "right"
} else if (img_position == "lowerleft") {
vjust_ <- "bottom"
hjust_ <- "left"
}
}
}
# ------------------------------------
# MAPS:
# specify logo location (which corner)
# ------------------------------------
else {
if (img_position == "upperleft") {
vjust_ <- "bottom"
hjust_ <- "left"
} else if (img_position == "upperright") {
vjust_ <- "bottom"
hjust_ <- "right"
} else if (img_position == "lowerright") {
vjust_ <- "top"
hjust_ <- "right"
} else if (img_position == "lowerleft") {
vjust_ <- "top"
hjust_ <- "left"
} else {
break
}
# ------------------------------------
# specify logo justification and placement
# ------------------------------------
if (is.na(xloc) & is.na(yloc)) {
if (img_just == "inside") {
if (img_position == "upperleft") {
x_ <- 0.02
y_ <- 0.8
} else if (img_position == "upperright") {
x_ <- 0.98
y_ <- 0.8
} else if (img_position == "lowerright") {
x_ <- 0.98
y_ <- 0.2
} else if (img_position == "lowerleft") {
x_ <- 0.02
y_ <- 0.2
} else if (img_position == 'center') {
x_ <- 0.5
y_ <- 0.5
}
} else if (img_just == "outside") {
if (img_position == "upperleft") {
x_ <- 0
y_ <- 0.9
} else if (img_position == "upperright") {
x_ <- 1
y_ <- 0.9
} else if (img_position == "lowerright") {
x_ <- 1
y_ <- 0.08
} else if (img_position == "lowerleft") {
x_ <- 0
y_ <- 0.08
} else if (img_position == 'center') {
x_ <- 0.5
y_ <- 0.5
}
} else if (img_just == "center") {
stop("Center justification on maps not supported")
}
}
else if (!is.na(xloc) & !is.na(yloc)) {
x_ <- xloc
y_ <- yloc
} else {
break
}
}
location_df <- tibble::tibble(
x = x_,
y = y_,
width = img_rel_size,
height = img_rel_size,
grob = list(ggplot2::ggplotGrob(ggplot() +
annotation_custom(image_) +
theme_void()))
)
plot_object +
ggpmisc::geom_grob_npc(
data = location_df,
aes(
label = grob,
npcx = x,
npcy = y,
vp.width = width,
vp.height = height
),
vjust = vjust_,
hjust = hjust_
)
}
myurl <- "https://www.r-project.org/logo/Rlogo.png"
z <- tempfile()
download.file(myurl,z,mode="wb")
pic <- readPNG(z)
file.remove(z) # cleanup
FALSE [1] TRUE
# convert to a rasterGrob
rlogo <- grid::rasterGrob(pic, interpolate=TRUE)
plot <- ggplot() +
geom_point(
data = palmerpenguins::penguins,
aes(flipper_length_mm, bill_length_mm, color = species)
)
# place image in lower left, inside the plot panel
add_image(plot_object = plot,
image_object = rlogo,
img_rel_size = 0.3,
img_position = "lowerleft",
img_just = "inside")
# upper right, inside plot panel, and bigger
add_image(plot_object = plot,
image_object = rlogo,
img_rel_size = 0.5,
img_position = "upperright",
img_just = "inside")
# place logo in the center of the plot
add_image(plot_object = plot,
image_object = rlogo,
img_rel_size = 0.3,
img_position = 'center',
img_just = "center")
# place logo off-center
add_image(plot_object = plot,
image_object = rlogo,
img_rel_size = 0.3,
xloc = 0.8,
yloc = 0.5,
img_just = "center")
# place logo under the plot on right side
add_image(plot_object = plot +
theme(plot.margin = margin(1, 1, 20, 1, unit = "mm")),
image_object = rlogo,
img_rel_size = 0.3,
img_position = "lowerright",
img_just = "outside")
# combining img_position and xloc/yloc for alternate placement
# pipe the plot into the add_image function
(plot +
theme(plot.margin = margin(1, 20, 1, 1, unit = "mm"))) %>%
add_image(
plot_object = .,
image_object = rlogo,
img_rel_size = 0.3,
yloc = 0,
xloc = 1,
img_position = "lowerleft"
)
land_sf <- rnaturalearth::ne_countries(scale = 110, returnclass = 'sf')
(ggplot() +
geom_sf(data = land_sf) +
theme_minimal()) %>%
add_image(plot_object = .,
img_rel_size = 0.2,
image_object = rlogo,
img_position = 'upperright',
img_just = 'outside')