Inserting an Image to Ggplot Outside the Chart Area

Inserting an image to ggplot outside the chart area

When faceting, annotation_custom draws the annotation in all panels. Therefore, annotation-custom might not be the best way to go. Here are two attempts using functions from the grid package. Neither is entirely automatic, but you might be able to adapt one or the other to meet your needs. They set up a 2 X 2 grid, shown using the grid.show.layout() command. In the first, the faceted plot fills the entire panel, and the top right viewport contains the logo. It just so happens that in your plot, there is clear space for the logo. Note how layout.pos.row and layout.pos.col give the rows and columns occupied by a viewport within the layout.

library(ggplot2)
library(png)
library(grid)

# Get the logo
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img)

# Set the size of the viewport to contain the logo
size = unit(2, "cm")

# Get the graph
d <- ggplot(diamonds, aes(carat, price)) +
xlim(0, 2) +
stat_binhex(na.rm = TRUE) +
labs(title = 'Title') +
theme(aspect.ratio = 1) +
facet_wrap(~ color, scales = "free_x")

# Set up the layout for grid
heights = unit.c(size, unit(1, "npc") - size)
widths = unit.c(unit(1, "npc") - size, size)
lo = grid.layout(2, 2, widths = widths, heights = heights)
# Show the layout
grid.show.layout(lo)

# Position the elements within the viewports
grid.newpage()
pushViewport(viewport(layout = lo))

# The plot
pushViewport(viewport(layout.pos.row=1:2, layout.pos.col = 1:2))
print(d, newpage=FALSE)
popViewport()

# The logo
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 2))
print(grid.draw(g), newpage=FALSE)
popViewport()
popViewport()

# To save the object
g = grid.grab()

grid.newpage()
grid.draw(g)

The title does not entirely align with the logo. One fix is to remove the title from the ggplot, draw a separate textGrob that contains the title, then position the textGrob in the top left viewport beside the viewport that contains the logo.

# Get the logo
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img)

# Set the size of the viewport to contain the logo
size = unit(2, "cm")

# Get the graph
d <- ggplot(diamonds, aes(carat, price)) +
xlim(0, 2) +
stat_binhex(na.rm = TRUE) +
# labs(title = 'Title') +
theme(aspect.ratio = 1) +
facet_wrap(~ color, scales = "free_x")

# and the title
title = textGrob("Title", gp = gpar(face = "bold", cex = 2))

# Set up the layout for grid
heights = unit.c(size, unit(1, "npc") - size)
widths = unit.c(unit(1, "npc") - 1.5*size, size)
lo = grid.layout(2, 2, widths = widths, heights = heights)
# Show the layout
grid.show.layout(lo)

# Position the elements within the viewports
grid.newpage()
pushViewport(viewport(layout = lo))

# The plot
pushViewport(viewport(layout.pos.row=2, layout.pos.col = 1:2))
print(d, newpage=FALSE)
popViewport()

# The logo
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 2))
print(grid.draw(g), newpage=FALSE)
popViewport()

# The title
pushViewport(viewport(layout.pos.row=1, layout.pos.col = 1))
print(grid.draw(title), newpage=FALSE)
popViewport()
popViewport()

# To save the object
g = grid.grab()

grid.newpage()
grid.draw(g)

Sample Image

Inserting an image to ggplot2

try ?annotation_custom in ggplot2

example,

library(png)
library(grid)
img <- readPNG(system.file("img", "Rlogo.png", package="png"))
g <- rasterGrob(img, interpolate=TRUE)

qplot(1:10, 1:10, geom="blank") +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_point()

How to add image to ggplot2 under the grid?

It's possible in the development version of ggplot2.

How to install it see this answer: https://stackoverflow.com/a/9656182/4265407

Minimal working example:

library(devtools)
dev_mode(on=T)

library(ggplot2)
library(png)
library(grid)

img <- readPNG(system.file("img", "Rlogo.png", package="png"), TRUE)
gpp <- rasterGrob(img, interpolate=TRUE)
gpp$width <- unit(1, "npc")
gpp$height <- unit(1, "npc")
df <- data.frame(x=seq(1,2,0.01),y=seq(1,2,0.01))
ggplot(df,aes(x=x,y=y)) +
annotation_custom(gpp, xmin=1, xmax=2.5, ymin=1, ymax=1.5) +
geom_point() + theme(panel.ontop=TRUE,
panel.background = element_rect(colour = NA,fill="transparent"))

How can I add a logo to a ggplot visualisation?

You could use the cowplot package to easily add an image to any plot made with ggplot. I used the R logo as the image that needs to be added to the plot (using magick package to read it). One advantage of using cowplot is that you can easily specify the size and position of both the plot and the image.

library(cowplot)
library(magick)

img <- image_read("Logo.png")

# Set the canvas where you are going to draw the plot and the image
ggdraw() +
# Draw the plot in the canvas setting the x and y positions, which go from 0,0
# (lower left corner) to 1,1 (upper right corner) and set the width and height of
# the plot. It's advisable that x + width = 1 and y + height = 1, to avoid clipping
# the plot
draw_plot(p,x = 0, y = 0.15, width = 1, height = 0.85) +
# Draw image in the canvas using the same concept as for the plot. Might need to
# play with the x, y, width and height values to obtain the desired result
draw_image(img,x = 0.85, y = 0.02, width = 0.15, height = 0.15)

Plot with image

Inserting an image to a bar chart in ggplot

One option is to use ggimage. Source: https://guangchuangyu.github.io/pkgdocs/ggimage.html. Try this:

library(ggplot2)
library(ggimage)
library(dplyr)

set.seed(1234)

img <- list.files(system.file("extdata", package="ggimage"),
pattern="png", full.names=TRUE)

df = data.frame(
group = c('a', 'b', 'c'),
value = 1:3,
image = sample(img, size=3, replace = TRUE)
) %>%
mutate(value1 = .5 * value)

ggplot(df, aes(group, value)) +
geom_col() +
geom_image(aes(image=image, y = value1), size=.2)

Sample Image

Created on 2020-03-19 by the reprex package (v0.3.0)

Add horizontal lines outside plot area in ggplot2

You can set coord_cartesian(clip = "off") and add a couple of annotation_customcalls. This allows plotting relative to the panel without having to specify co-ordinates relative to your data:

ggplot(midwest, aes(x=area, y=poptotal)) + 
geom_point(aes(col=state, size=popdensity)) +
geom_smooth(method="loess", se=F) +
xlim(c(0, 0.1)) +
ylim(c(0, 500000)) +
labs(y="Population",
x="Area",
title="FIGURE 4: Scatterplot",
caption = "Source: midwest") +
coord_cartesian(clip = "off") +
annotation_custom(grid::linesGrob(x = c(-0.12, 1.19), y = c(1.03, 1.03))) +
annotation_custom(grid::linesGrob(x = c(-0.12, 1.19), y = c(-.07, -.07))) +
theme(plot.background = element_rect(colour="black", size = 1),
plot.title = element_text(size = 16, face = 2, vjust = 5, hjust = -0.2),
plot.margin = margin(20, 20, 20, 20))

Sample Image

Add text outside plot area

I'm not entirely sure what you're trying to do so this may or may not generalise well.

That said, one possibility is to use annotate with coord_cartesian(clip = "off") to allow text outside the plot area.

ggplot(mtcars, aes(mpg, cyl, color = vs)) +
geom_line() +
annotate("text", x = 12.5, y = 3.5, label = "Arbitrary text") +
coord_cartesian(ylim = c(4, 8), clip = "off")

Sample Image

ggplot adding image on top-right in two plots with different scales

We can automate the process of specifying the location and scales, so that you don't need to change the locations manually, as shown in the following example:

get.xy <- function(p) {
g_data <- ggplot_build(p)
data.frame(xmax = max(g_data$data[[1]]$x),
ymax = max(g_data$data[[1]]$y),
xmin = min(g_data$data[[1]]$x),
ymin = min(g_data$data[[1]]$y))
}

# this returns the dataframe with required x, y params for annotation_custom,
# ensuring the size and position of the image constant
get.params.df <- function(p0, p1, width, height) {
df0 <- cbind.data.frame(get.xy(p0), width=width, height=height)
df1 <- cbind.data.frame(get.xy(p1))
df1$width <- df0$width*(df1$xmax-df1$xmin)/(df0$xmax-df0$xmin)
df1$height <- df0$height*(df1$ymax-df1$ymin)/(df0$ymax-df0$ymin)
df <- rbind(df0, df1)
return(data.frame(xmin=df$xmax-df$width, xmax=df$xmax+df$width, ymin=df$ymax-df$height, ymax=df$ymax+df$height))
}

p0 <- plt(am0)
p1 <- plt(am1)

df <- get.params.df(p0, p1, width=10, height=10)

# adding image
library(gridExtra)
grid.arrange(
p0 + annotation_custom(rasterGrob(img), xmin=df[1,1],xmax=df[1,2], ymin=df[1,3], ymax=df[1,4]),
p1 + annotation_custom(rasterGrob(img), xmin=df[2,1],xmax=df[2,2], ymin=df[2,3], ymax=df[2,4])
)

Sample Image

If you want bigger image change the width height parameter only, everything else remains unchanged.

df <- get.params.df(p0, p1, width=25, height=25)
library(gridExtra)
grid.arrange(
p0 + annotation_custom(rasterGrob(img), xmin=df[1,1],xmax=df[1,2], ymin=df[1,3], ymax=df[1,4]),
p1 + annotation_custom(rasterGrob(img), xmin=df[2,1],xmax=df[2,2], ymin=df[2,3], ymax=df[2,4])
)

Sample Image



Related Topics



Leave a reply



Submit